1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package android.support.v14.preference;
18
19import android.app.AlertDialog;
20import android.app.Dialog;
21import android.app.DialogFragment;
22import android.app.Fragment;
23import android.content.Context;
24import android.content.DialogInterface;
25import android.os.Bundle;
26import android.support.annotation.NonNull;
27import android.support.v7.preference.DialogPreference;
28import android.text.TextUtils;
29import android.view.LayoutInflater;
30import android.view.View;
31import android.view.Window;
32import android.view.WindowManager;
33import android.widget.TextView;
34
35public abstract class PreferenceDialogFragment extends DialogFragment implements
36        DialogInterface.OnClickListener {
37
38    protected static final String ARG_KEY = "key";
39
40    private DialogPreference mPreference;
41
42    /** Which button was clicked. */
43    private int mWhichButtonClicked;
44
45    @Override
46    public void onCreate(Bundle savedInstanceState) {
47        super.onCreate(savedInstanceState);
48
49        final Fragment rawFragment = getTargetFragment();
50        if (!(rawFragment instanceof DialogPreference.TargetFragment)) {
51            throw new IllegalStateException("Target fragment must implement TargetFragment" +
52                    " interface");
53        }
54
55        final DialogPreference.TargetFragment fragment =
56                (DialogPreference.TargetFragment) rawFragment;
57
58        final String key = getArguments().getString(ARG_KEY);
59        mPreference = (DialogPreference) fragment.findPreference(key);
60    }
61
62    @Override
63    public @NonNull
64    Dialog onCreateDialog(Bundle savedInstanceState) {
65        final Context context = getActivity();
66        mWhichButtonClicked = DialogInterface.BUTTON_NEGATIVE;
67
68        final AlertDialog.Builder builder = new AlertDialog.Builder(context)
69                .setTitle(mPreference.getDialogTitle())
70                .setIcon(mPreference.getDialogIcon())
71                .setPositiveButton(mPreference.getPositiveButtonText(), this)
72                .setNegativeButton(mPreference.getNegativeButtonText(), this);
73
74        View contentView = onCreateDialogView(context);
75        if (contentView != null) {
76            onBindDialogView(contentView);
77            builder.setView(contentView);
78        } else {
79            builder.setMessage(mPreference.getDialogMessage());
80        }
81
82        onPrepareDialogBuilder(builder);
83
84        // Create the dialog
85        final Dialog dialog = builder.create();
86        if (needInputMethod()) {
87            requestInputMethod(dialog);
88        }
89
90
91        return builder.create();
92    }
93
94    /**
95     * Get the preference that requested this dialog. Available after {@link #onCreate(Bundle)} has
96     * been called.
97     *
98     * @return The {@link DialogPreference} associated with this
99     * dialog.
100     */
101    public DialogPreference getPreference() {
102        return mPreference;
103    }
104
105    /**
106     * Prepares the dialog builder to be shown when the preference is clicked.
107     * Use this to set custom properties on the dialog.
108     * <p>
109     * Do not {@link AlertDialog.Builder#create()} or
110     * {@link AlertDialog.Builder#show()}.
111     */
112    protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {}
113
114    /**
115     * Returns whether the preference needs to display a soft input method when the dialog
116     * is displayed. Default is false. Subclasses should override this method if they need
117     * the soft input method brought up automatically.
118     * @hide
119     */
120    protected boolean needInputMethod() {
121        return false;
122    }
123
124    /**
125     * Sets the required flags on the dialog window to enable input method window to show up.
126     */
127    private void requestInputMethod(Dialog dialog) {
128        Window window = dialog.getWindow();
129        window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
130    }
131
132    /**
133     * Creates the content view for the dialog (if a custom content view is
134     * required). By default, it inflates the dialog layout resource if it is
135     * set.
136     *
137     * @return The content View for the dialog.
138     * @see DialogPreference#setLayoutResource(int)
139     */
140    protected View onCreateDialogView(Context context) {
141        final int resId = mPreference.getDialogLayoutResource();
142        if (resId == 0) {
143            return null;
144        }
145
146        LayoutInflater inflater = LayoutInflater.from(context);
147        return inflater.inflate(resId, null);
148    }
149
150    /**
151     * Binds views in the content View of the dialog to data.
152     * <p>
153     * Make sure to call through to the superclass implementation.
154     *
155     * @param view The content View of the dialog, if it is custom.
156     */
157    protected void onBindDialogView(View view) {
158        View dialogMessageView = view.findViewById(android.R.id.message);
159
160        if (dialogMessageView != null) {
161            final CharSequence message = mPreference.getDialogMessage();
162            int newVisibility = View.GONE;
163
164            if (!TextUtils.isEmpty(message)) {
165                if (dialogMessageView instanceof TextView) {
166                    ((TextView) dialogMessageView).setText(message);
167                }
168
169                newVisibility = View.VISIBLE;
170            }
171
172            if (dialogMessageView.getVisibility() != newVisibility) {
173                dialogMessageView.setVisibility(newVisibility);
174            }
175        }
176    }
177
178    @Override
179    public void onClick(DialogInterface dialog, int which) {
180        mWhichButtonClicked = which;
181    }
182
183    @Override
184    public void onDismiss(DialogInterface dialog) {
185        super.onDismiss(dialog);
186        onDialogClosed(mWhichButtonClicked == DialogInterface.BUTTON_POSITIVE);
187    }
188
189    public abstract void onDialogClosed(boolean positiveResult);
190}
191