1 /*
2  * Copyright 2019 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 
17 package com.android.car.ui.preference;
18 
19 import android.app.AlertDialog;
20 import android.os.Bundle;
21 import android.text.InputType;
22 import android.view.KeyEvent;
23 import android.view.View;
24 import android.view.inputmethod.EditorInfo;
25 import android.widget.EditText;
26 import android.widget.TextView;
27 
28 import androidx.annotation.NonNull;
29 import androidx.preference.EditTextPreference;
30 
31 import com.android.car.ui.utils.CarUiUtils;
32 
33 /**
34  * Presents a dialog with an {@link EditText} associated with an {@link EditTextPreference}.
35  *
36  * <p>Note: this is borrowed as-is from androidx.preference.EditTextPreferenceDialogFragmentCompat
37  * with updates to formatting to match the project style. Automotive applications should use this
38  * implementations in order to launch the system themed platform {@link AlertDialog} instead of the
39  * one in the support library.
40  */
41 public class EditTextPreferenceDialogFragment extends PreferenceDialogFragment implements
42         TextView.OnEditorActionListener {
43 
44     private static final String SAVE_STATE_TEXT = "EditTextPreferenceDialogFragment.text";
45 
46     private EditText mEditText;
47     private CharSequence mText;
48     private boolean mAllowEnterToSubmit = true;
49 
50     /**
51      * Returns a new instance of {@link EditTextPreferenceDialogFragment} for the {@link
52      * EditTextPreference} with the given {@code key}.
53      */
54     @NonNull
newInstance(String key)55     public static EditTextPreferenceDialogFragment newInstance(String key) {
56         EditTextPreferenceDialogFragment fragment =
57                 new EditTextPreferenceDialogFragment();
58         Bundle b = new Bundle(/* capacity= */ 1);
59         b.putString(ARG_KEY, key);
60         fragment.setArguments(b);
61         return fragment;
62     }
63 
64     @Override
onCreate(Bundle savedInstanceState)65     public void onCreate(Bundle savedInstanceState) {
66         super.onCreate(savedInstanceState);
67         if (savedInstanceState == null) {
68             mText = getEditTextPreference().getText();
69         } else {
70             mText = savedInstanceState.getCharSequence(SAVE_STATE_TEXT);
71         }
72     }
73 
74     @Override
onSaveInstanceState(@onNull Bundle outState)75     public void onSaveInstanceState(@NonNull Bundle outState) {
76         super.onSaveInstanceState(outState);
77         outState.putCharSequence(SAVE_STATE_TEXT, mText);
78     }
79 
80     @Override
onBindDialogView(@onNull View view)81     protected void onBindDialogView(@NonNull View view) {
82         super.onBindDialogView(view);
83 
84         mEditText = CarUiUtils.findViewByRefId(view, android.R.id.edit);
85 
86         if (mEditText == null) {
87             throw new IllegalStateException(
88                     "Dialog view must contain an EditText with id @android:id/edit");
89         }
90 
91         mEditText.requestFocus();
92         mEditText.setText(mText);
93         mEditText.setInputType(InputType.TYPE_CLASS_TEXT);
94         mEditText.setImeOptions(EditorInfo.IME_ACTION_DONE);
95         mEditText.setOnEditorActionListener(this);
96 
97         // Place cursor at the end
98         mEditText.setSelection(mEditText.getText().length());
99     }
100 
getEditTextPreference()101     private EditTextPreference getEditTextPreference() {
102         return (EditTextPreference) getPreference();
103     }
104 
105     @Override
needInputMethod()106     protected boolean needInputMethod() {
107         return true;
108     }
109 
110     @Override
onDialogClosed(boolean positiveResult)111     protected void onDialogClosed(boolean positiveResult) {
112         if (positiveResult) {
113             String value = mEditText.getText().toString();
114             if (getEditTextPreference().callChangeListener(value)) {
115                 getEditTextPreference().setText(value);
116             }
117         }
118     }
119 
120     /** Allows enabling and disabling the ability to press enter to dismiss the dialog. */
setAllowEnterToSubmit(boolean isAllowed)121     public void setAllowEnterToSubmit(boolean isAllowed) {
122         mAllowEnterToSubmit = isAllowed;
123     }
124 
125     /** Allows verifying if enter to submit is currently enabled. */
getAllowEnterToSubmit()126     public boolean getAllowEnterToSubmit() {
127         return mAllowEnterToSubmit;
128     }
129 
130     @Override
onEditorAction(TextView v, int actionId, KeyEvent event)131     public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
132         if (actionId == EditorInfo.IME_ACTION_DONE && mAllowEnterToSubmit) {
133             CharSequence newValue = v.getText();
134 
135             getEditTextPreference().callChangeListener(newValue);
136             dismiss();
137 
138             return true;
139         }
140         return false;
141     }
142 }
143