1 /* 2 * Copyright (C) 2011 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.settings.bluetooth; 18 19 import android.app.AlertDialog; 20 import android.app.Dialog; 21 import android.content.Context; 22 import android.content.DialogInterface; 23 import android.content.res.Configuration; 24 import android.os.Bundle; 25 import android.text.Editable; 26 import android.text.InputFilter; 27 import android.text.TextUtils; 28 import android.text.TextWatcher; 29 import android.view.KeyEvent; 30 import android.view.LayoutInflater; 31 import android.view.View; 32 import android.view.WindowManager; 33 import android.view.inputmethod.EditorInfo; 34 import android.view.inputmethod.InputMethodManager; 35 import android.widget.Button; 36 import android.widget.EditText; 37 import android.widget.TextView; 38 39 import com.android.settings.R; 40 import com.android.settings.core.instrumentation.InstrumentedDialogFragment; 41 42 /** 43 * Dialog fragment for renaming a Bluetooth device. 44 */ 45 abstract class BluetoothNameDialogFragment extends InstrumentedDialogFragment 46 implements TextWatcher { 47 private AlertDialog mAlertDialog; 48 private Button mOkButton; 49 50 EditText mDeviceNameView; 51 52 // This flag is set when the name is updated by code, to distinguish from user changes 53 private boolean mDeviceNameUpdated; 54 55 // This flag is set when the user edits the name (preserved on rotation) 56 private boolean mDeviceNameEdited; 57 58 // Key to save the edited name and edit status for restoring after rotation 59 private static final String KEY_NAME = "device_name"; 60 private static final String KEY_NAME_EDITED = "device_name_edited"; 61 62 /** 63 * @return the title to use for the dialog. 64 */ 65 abstract protected int getDialogTitle(); 66 67 /** 68 * @return the current name used for this device. 69 */ 70 abstract protected String getDeviceName(); 71 72 /** 73 * Set the device to the given name. 74 * @param deviceName the name to use 75 */ 76 abstract protected void setDeviceName(String deviceName); 77 78 @Override 79 public Dialog onCreateDialog(Bundle savedInstanceState) { 80 String deviceName = getDeviceName(); 81 if (savedInstanceState != null) { 82 deviceName = savedInstanceState.getString(KEY_NAME, deviceName); 83 mDeviceNameEdited = savedInstanceState.getBoolean(KEY_NAME_EDITED, false); 84 } 85 AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()) 86 .setTitle(getDialogTitle()) 87 .setView(createDialogView(deviceName)) 88 .setPositiveButton(R.string.bluetooth_rename_button, (dialog, which) -> { 89 setDeviceName(mDeviceNameView.getText().toString()); 90 }) 91 .setNegativeButton(android.R.string.cancel, null); 92 mAlertDialog = builder.create(); 93 mAlertDialog.setOnShowListener(d -> { 94 if (mDeviceNameView != null && mDeviceNameView.requestFocus()) { 95 InputMethodManager imm = (InputMethodManager) getContext().getSystemService( 96 Context.INPUT_METHOD_SERVICE); 97 if (imm != null) { 98 imm.showSoftInput(mDeviceNameView, InputMethodManager.SHOW_IMPLICIT); 99 } 100 } 101 }); 102 103 return mAlertDialog; 104 } 105 106 @Override 107 public void onSaveInstanceState(Bundle outState) { 108 outState.putString(KEY_NAME, mDeviceNameView.getText().toString()); 109 outState.putBoolean(KEY_NAME_EDITED, mDeviceNameEdited); 110 } 111 112 private View createDialogView(String deviceName) { 113 final LayoutInflater layoutInflater = (LayoutInflater)getActivity() 114 .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 115 View view = layoutInflater.inflate(R.layout.dialog_edittext, null); 116 mDeviceNameView = (EditText) view.findViewById(R.id.edittext); 117 mDeviceNameView.setFilters(new InputFilter[] { 118 new BluetoothLengthDeviceNameFilter() 119 }); 120 mDeviceNameView.setText(deviceName); // set initial value before adding listener 121 if (!TextUtils.isEmpty(deviceName)) { 122 mDeviceNameView.setSelection(deviceName.length()); 123 } 124 mDeviceNameView.addTextChangedListener(this); 125 com.android.settings.Utils.setEditTextCursorPosition(mDeviceNameView); 126 mDeviceNameView.setOnEditorActionListener(new TextView.OnEditorActionListener() { 127 @Override 128 public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { 129 if (actionId == EditorInfo.IME_ACTION_DONE) { 130 setDeviceName(v.getText().toString()); 131 mAlertDialog.dismiss(); 132 return true; // action handled 133 } else { 134 return false; // not handled 135 } 136 } 137 }); 138 return view; 139 } 140 141 @Override 142 public void onDestroy() { 143 super.onDestroy(); 144 mAlertDialog = null; 145 mDeviceNameView = null; 146 mOkButton = null; 147 } 148 149 @Override 150 public void onResume() { 151 super.onResume(); 152 if (mOkButton == null) { 153 mOkButton = mAlertDialog.getButton(DialogInterface.BUTTON_POSITIVE); 154 mOkButton.setEnabled(mDeviceNameEdited); // Ok button enabled after user edits 155 } 156 } 157 158 void updateDeviceName() { 159 String name = getDeviceName(); 160 if (name != null) { 161 mDeviceNameUpdated = true; 162 mDeviceNameEdited = false; 163 mDeviceNameView.setText(name); 164 } 165 } 166 167 public void afterTextChanged(Editable s) { 168 if (mDeviceNameUpdated) { 169 // Device name changed by code; disable Ok button until edited by user 170 mDeviceNameUpdated = false; 171 mOkButton.setEnabled(false); 172 } else { 173 mDeviceNameEdited = true; 174 if (mOkButton != null) { 175 mOkButton.setEnabled(s.toString().trim().length() != 0); 176 } 177 } 178 } 179 180 public void onConfigurationChanged(Configuration newConfig, CharSequence s) { 181 super.onConfigurationChanged(newConfig); 182 if (mOkButton != null) { 183 mOkButton.setEnabled(s.length() != 0 && !(s.toString().trim().isEmpty())); 184 } 185 } 186 187 /* Not used */ 188 public void beforeTextChanged(CharSequence s, int start, int count, int after) { 189 } 190 191 /* Not used */ 192 public void onTextChanged(CharSequence s, int start, int before, int count) { 193 } 194 } 195