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