479 lines
16 KiB
Java
479 lines
16 KiB
Java
|
/*
|
||
|
* 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 android.preference;
|
||
|
|
||
|
|
||
|
import android.app.AlertDialog;
|
||
|
import android.app.Dialog;
|
||
|
import android.content.Context;
|
||
|
import android.content.DialogInterface;
|
||
|
import android.content.SharedPreferences;
|
||
|
import android.content.res.TypedArray;
|
||
|
import android.graphics.drawable.Drawable;
|
||
|
import android.os.Bundle;
|
||
|
import android.os.Parcel;
|
||
|
import android.os.Parcelable;
|
||
|
import android.text.TextUtils;
|
||
|
import android.util.AttributeSet;
|
||
|
import android.view.LayoutInflater;
|
||
|
import android.view.View;
|
||
|
import android.view.Window;
|
||
|
import android.view.WindowManager;
|
||
|
import android.widget.TextView;
|
||
|
|
||
|
/**
|
||
|
* A base class for {@link Preference} objects that are
|
||
|
* dialog-based. These preferences will, when clicked, open a dialog showing the
|
||
|
* actual preference controls.
|
||
|
*
|
||
|
* @attr ref android.R.styleable#DialogPreference_dialogTitle
|
||
|
* @attr ref android.R.styleable#DialogPreference_dialogMessage
|
||
|
* @attr ref android.R.styleable#DialogPreference_dialogIcon
|
||
|
* @attr ref android.R.styleable#DialogPreference_dialogLayout
|
||
|
* @attr ref android.R.styleable#DialogPreference_positiveButtonText
|
||
|
* @attr ref android.R.styleable#DialogPreference_negativeButtonText
|
||
|
*/
|
||
|
public abstract class DialogPreference extends Preference implements
|
||
|
DialogInterface.OnClickListener, DialogInterface.OnDismissListener,
|
||
|
PreferenceManager.OnActivityDestroyListener {
|
||
|
private AlertDialog.Builder mBuilder;
|
||
|
|
||
|
private CharSequence mDialogTitle;
|
||
|
private CharSequence mDialogMessage;
|
||
|
private Drawable mDialogIcon;
|
||
|
private CharSequence mPositiveButtonText;
|
||
|
private CharSequence mNegativeButtonText;
|
||
|
private int mDialogLayoutResId;
|
||
|
|
||
|
/** The dialog, if it is showing. */
|
||
|
private Dialog mDialog;
|
||
|
|
||
|
/** Which button was clicked. */
|
||
|
private int mWhichButtonClicked;
|
||
|
|
||
|
public DialogPreference(Context context, AttributeSet attrs, int defStyle) {
|
||
|
super(context, attrs, defStyle);
|
||
|
|
||
|
TypedArray a = context.obtainStyledAttributes(attrs,
|
||
|
com.android.internal.R.styleable.DialogPreference, defStyle, 0);
|
||
|
mDialogTitle = a.getString(com.android.internal.R.styleable.DialogPreference_dialogTitle);
|
||
|
if (mDialogTitle == null) {
|
||
|
// Fallback on the regular title of the preference
|
||
|
// (the one that is seen in the list)
|
||
|
mDialogTitle = getTitle();
|
||
|
}
|
||
|
mDialogMessage = a.getString(com.android.internal.R.styleable.DialogPreference_dialogMessage);
|
||
|
mDialogIcon = a.getDrawable(com.android.internal.R.styleable.DialogPreference_dialogIcon);
|
||
|
mPositiveButtonText = a.getString(com.android.internal.R.styleable.DialogPreference_positiveButtonText);
|
||
|
mNegativeButtonText = a.getString(com.android.internal.R.styleable.DialogPreference_negativeButtonText);
|
||
|
mDialogLayoutResId = a.getResourceId(com.android.internal.R.styleable.DialogPreference_dialogLayout,
|
||
|
mDialogLayoutResId);
|
||
|
a.recycle();
|
||
|
|
||
|
}
|
||
|
|
||
|
public DialogPreference(Context context, AttributeSet attrs) {
|
||
|
this(context, attrs, com.android.internal.R.attr.dialogPreferenceStyle);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the title of the dialog. This will be shown on subsequent dialogs.
|
||
|
*
|
||
|
* @param dialogTitle The title.
|
||
|
*/
|
||
|
public void setDialogTitle(CharSequence dialogTitle) {
|
||
|
mDialogTitle = dialogTitle;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @see #setDialogTitle(CharSequence)
|
||
|
* @param dialogTitleResId The dialog title as a resource.
|
||
|
*/
|
||
|
public void setDialogTitle(int dialogTitleResId) {
|
||
|
setDialogTitle(getContext().getString(dialogTitleResId));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the title to be shown on subsequent dialogs.
|
||
|
* @return The title.
|
||
|
*/
|
||
|
public CharSequence getDialogTitle() {
|
||
|
return mDialogTitle;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the message of the dialog. This will be shown on subsequent dialogs.
|
||
|
* <p>
|
||
|
* This message forms the content View of the dialog and conflicts with
|
||
|
* list-based dialogs, for example. If setting a custom View on a dialog via
|
||
|
* {@link #setDialogLayoutResource(int)}, include a text View with ID
|
||
|
* {@link android.R.id#message} and it will be populated with this message.
|
||
|
*
|
||
|
* @param dialogMessage The message.
|
||
|
*/
|
||
|
public void setDialogMessage(CharSequence dialogMessage) {
|
||
|
mDialogMessage = dialogMessage;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @see #setDialogMessage(CharSequence)
|
||
|
* @param dialogMessageResId The dialog message as a resource.
|
||
|
*/
|
||
|
public void setDialogMessage(int dialogMessageResId) {
|
||
|
setDialogMessage(getContext().getString(dialogMessageResId));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the message to be shown on subsequent dialogs.
|
||
|
* @return The message.
|
||
|
*/
|
||
|
public CharSequence getDialogMessage() {
|
||
|
return mDialogMessage;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the icon of the dialog. This will be shown on subsequent dialogs.
|
||
|
*
|
||
|
* @param dialogIcon The icon, as a {@link Drawable}.
|
||
|
*/
|
||
|
public void setDialogIcon(Drawable dialogIcon) {
|
||
|
mDialogIcon = dialogIcon;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the icon (resource ID) of the dialog. This will be shown on
|
||
|
* subsequent dialogs.
|
||
|
*
|
||
|
* @param dialogIconRes The icon, as a resource ID.
|
||
|
*/
|
||
|
public void setDialogIcon(int dialogIconRes) {
|
||
|
mDialogIcon = getContext().getResources().getDrawable(dialogIconRes);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the icon to be shown on subsequent dialogs.
|
||
|
* @return The icon, as a {@link Drawable}.
|
||
|
*/
|
||
|
public Drawable getDialogIcon() {
|
||
|
return mDialogIcon;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the text of the positive button of the dialog. This will be shown on
|
||
|
* subsequent dialogs.
|
||
|
*
|
||
|
* @param positiveButtonText The text of the positive button.
|
||
|
*/
|
||
|
public void setPositiveButtonText(CharSequence positiveButtonText) {
|
||
|
mPositiveButtonText = positiveButtonText;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @see #setPositiveButtonText(CharSequence)
|
||
|
* @param positiveButtonTextResId The positive button text as a resource.
|
||
|
*/
|
||
|
public void setPositiveButtonText(int positiveButtonTextResId) {
|
||
|
setPositiveButtonText(getContext().getString(positiveButtonTextResId));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the text of the positive button to be shown on subsequent
|
||
|
* dialogs.
|
||
|
*
|
||
|
* @return The text of the positive button.
|
||
|
*/
|
||
|
public CharSequence getPositiveButtonText() {
|
||
|
return mPositiveButtonText;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the text of the negative button of the dialog. This will be shown on
|
||
|
* subsequent dialogs.
|
||
|
*
|
||
|
* @param negativeButtonText The text of the negative button.
|
||
|
*/
|
||
|
public void setNegativeButtonText(CharSequence negativeButtonText) {
|
||
|
mNegativeButtonText = negativeButtonText;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @see #setNegativeButtonText(CharSequence)
|
||
|
* @param negativeButtonTextResId The negative button text as a resource.
|
||
|
*/
|
||
|
public void setNegativeButtonText(int negativeButtonTextResId) {
|
||
|
setNegativeButtonText(getContext().getString(negativeButtonTextResId));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the text of the negative button to be shown on subsequent
|
||
|
* dialogs.
|
||
|
*
|
||
|
* @return The text of the negative button.
|
||
|
*/
|
||
|
public CharSequence getNegativeButtonText() {
|
||
|
return mNegativeButtonText;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the layout resource that is inflated as the {@link View} to be shown
|
||
|
* as the content View of subsequent dialogs.
|
||
|
*
|
||
|
* @param dialogLayoutResId The layout resource ID to be inflated.
|
||
|
* @see #setDialogMessage(CharSequence)
|
||
|
*/
|
||
|
public void setDialogLayoutResource(int dialogLayoutResId) {
|
||
|
mDialogLayoutResId = dialogLayoutResId;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the layout resource that is used as the content View for
|
||
|
* subsequent dialogs.
|
||
|
*
|
||
|
* @return The layout resource.
|
||
|
*/
|
||
|
public int getDialogLayoutResource() {
|
||
|
return mDialogLayoutResId;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Prepares the dialog builder to be shown when the preference is clicked.
|
||
|
* Use this to set custom properties on the dialog.
|
||
|
* <p>
|
||
|
* Do not {@link AlertDialog.Builder#create()} or
|
||
|
* {@link AlertDialog.Builder#show()}.
|
||
|
*/
|
||
|
protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
protected void onClick() {
|
||
|
showDialog(null);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Shows the dialog associated with this Preference. This is normally initiated
|
||
|
* automatically on clicking on the preference. Call this method if you need to
|
||
|
* show the dialog on some other event.
|
||
|
*
|
||
|
* @param state Optional instance state to restore on the dialog
|
||
|
*/
|
||
|
protected void showDialog(Bundle state) {
|
||
|
Context context = getContext();
|
||
|
|
||
|
mWhichButtonClicked = DialogInterface.BUTTON_NEGATIVE;
|
||
|
|
||
|
mBuilder = new AlertDialog.Builder(context)
|
||
|
.setTitle(mDialogTitle)
|
||
|
.setIcon(mDialogIcon)
|
||
|
.setPositiveButton(mPositiveButtonText, this)
|
||
|
.setNegativeButton(mNegativeButtonText, this);
|
||
|
|
||
|
View contentView = onCreateDialogView();
|
||
|
if (contentView != null) {
|
||
|
onBindDialogView(contentView);
|
||
|
mBuilder.setView(contentView);
|
||
|
} else {
|
||
|
mBuilder.setMessage(mDialogMessage);
|
||
|
}
|
||
|
|
||
|
onPrepareDialogBuilder(mBuilder);
|
||
|
|
||
|
getPreferenceManager().registerOnActivityDestroyListener(this);
|
||
|
|
||
|
// Create the dialog
|
||
|
final Dialog dialog = mDialog = mBuilder.create();
|
||
|
if (state != null) {
|
||
|
dialog.onRestoreInstanceState(state);
|
||
|
}
|
||
|
if (needInputMethod()) {
|
||
|
requestInputMethod(dialog);
|
||
|
}
|
||
|
dialog.setOnDismissListener(this);
|
||
|
dialog.show();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns whether the preference needs to display a soft input method when the dialog
|
||
|
* is displayed. Default is false. Subclasses should override this method if they need
|
||
|
* the soft input method brought up automatically.
|
||
|
* @hide
|
||
|
*/
|
||
|
protected boolean needInputMethod() {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the required flags on the dialog window to enable input method window to show up.
|
||
|
*/
|
||
|
private void requestInputMethod(Dialog dialog) {
|
||
|
Window window = dialog.getWindow();
|
||
|
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE |
|
||
|
WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Creates the content view for the dialog (if a custom content view is
|
||
|
* required). By default, it inflates the dialog layout resource if it is
|
||
|
* set.
|
||
|
*
|
||
|
* @return The content View for the dialog.
|
||
|
* @see #setLayoutResource(int)
|
||
|
*/
|
||
|
protected View onCreateDialogView() {
|
||
|
if (mDialogLayoutResId == 0) {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
|
||
|
Context.LAYOUT_INFLATER_SERVICE);
|
||
|
return inflater.inflate(mDialogLayoutResId, null);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Binds views in the content View of the dialog to data.
|
||
|
* <p>
|
||
|
* Make sure to call through to the superclass implementation.
|
||
|
*
|
||
|
* @param view The content View of the dialog, if it is custom.
|
||
|
*/
|
||
|
protected void onBindDialogView(View view) {
|
||
|
View dialogMessageView = view.findViewById(com.android.internal.R.id.message);
|
||
|
|
||
|
if (dialogMessageView != null) {
|
||
|
final CharSequence message = getDialogMessage();
|
||
|
int newVisibility = View.GONE;
|
||
|
|
||
|
if (!TextUtils.isEmpty(message)) {
|
||
|
if (dialogMessageView instanceof TextView) {
|
||
|
((TextView) dialogMessageView).setText(message);
|
||
|
}
|
||
|
|
||
|
newVisibility = View.VISIBLE;
|
||
|
}
|
||
|
|
||
|
if (dialogMessageView.getVisibility() != newVisibility) {
|
||
|
dialogMessageView.setVisibility(newVisibility);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void onClick(DialogInterface dialog, int which) {
|
||
|
mWhichButtonClicked = which;
|
||
|
}
|
||
|
|
||
|
public void onDismiss(DialogInterface dialog) {
|
||
|
|
||
|
getPreferenceManager().unregisterOnActivityDestroyListener(this);
|
||
|
|
||
|
mDialog = null;
|
||
|
onDialogClosed(mWhichButtonClicked == DialogInterface.BUTTON_POSITIVE);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Called when the dialog is dismissed and should be used to save data to
|
||
|
* the {@link SharedPreferences}.
|
||
|
*
|
||
|
* @param positiveResult Whether the positive button was clicked (true), or
|
||
|
* the negative button was clicked or the dialog was canceled (false).
|
||
|
*/
|
||
|
protected void onDialogClosed(boolean positiveResult) {
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Gets the dialog that is shown by this preference.
|
||
|
*
|
||
|
* @return The dialog, or null if a dialog is not being shown.
|
||
|
*/
|
||
|
public Dialog getDialog() {
|
||
|
return mDialog;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* {@inheritDoc}
|
||
|
*/
|
||
|
public void onActivityDestroy() {
|
||
|
|
||
|
if (mDialog == null || !mDialog.isShowing()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
mDialog.dismiss();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
protected Parcelable onSaveInstanceState() {
|
||
|
final Parcelable superState = super.onSaveInstanceState();
|
||
|
if (mDialog == null || !mDialog.isShowing()) {
|
||
|
return superState;
|
||
|
}
|
||
|
|
||
|
final SavedState myState = new SavedState(superState);
|
||
|
myState.isDialogShowing = true;
|
||
|
myState.dialogBundle = mDialog.onSaveInstanceState();
|
||
|
return myState;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
protected void onRestoreInstanceState(Parcelable state) {
|
||
|
if (state == null || !state.getClass().equals(SavedState.class)) {
|
||
|
// Didn't save state for us in onSaveInstanceState
|
||
|
super.onRestoreInstanceState(state);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
SavedState myState = (SavedState) state;
|
||
|
super.onRestoreInstanceState(myState.getSuperState());
|
||
|
if (myState.isDialogShowing) {
|
||
|
showDialog(myState.dialogBundle);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static class SavedState extends BaseSavedState {
|
||
|
boolean isDialogShowing;
|
||
|
Bundle dialogBundle;
|
||
|
|
||
|
public SavedState(Parcel source) {
|
||
|
super(source);
|
||
|
isDialogShowing = source.readInt() == 1;
|
||
|
dialogBundle = source.readBundle();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void writeToParcel(Parcel dest, int flags) {
|
||
|
super.writeToParcel(dest, flags);
|
||
|
dest.writeInt(isDialogShowing ? 1 : 0);
|
||
|
dest.writeBundle(dialogBundle);
|
||
|
}
|
||
|
|
||
|
public SavedState(Parcelable superState) {
|
||
|
super(superState);
|
||
|
}
|
||
|
|
||
|
public static final Parcelable.Creator<SavedState> CREATOR =
|
||
|
new Parcelable.Creator<SavedState>() {
|
||
|
public SavedState createFromParcel(Parcel in) {
|
||
|
return new SavedState(in);
|
||
|
}
|
||
|
|
||
|
public SavedState[] newArray(int size) {
|
||
|
return new SavedState[size];
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
}
|