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.app.DialogFragment; 22 import android.bluetooth.BluetoothAdapter; 23 import android.content.BroadcastReceiver; 24 import android.content.Context; 25 import android.content.DialogInterface; 26 import android.content.Intent; 27 import android.content.IntentFilter; 28 import android.content.res.Configuration; 29 import android.os.Bundle; 30 import android.text.Editable; 31 import android.text.InputFilter; 32 import android.text.TextWatcher; 33 import android.util.Log; 34 import android.view.KeyEvent; 35 import android.view.LayoutInflater; 36 import android.view.View; 37 import android.view.WindowManager; 38 import android.view.inputmethod.EditorInfo; 39 import android.widget.Button; 40 import android.widget.EditText; 41 import android.widget.TextView; 42 43 import com.android.internal.logging.nano.MetricsProto; 44 import com.android.settings.R; 45 import com.android.settings.core.instrumentation.InstrumentedDialogFragment; 46 import com.android.settingslib.bluetooth.LocalBluetoothAdapter; 47 import com.android.settingslib.bluetooth.LocalBluetoothManager; 48 49 /** 50 * Dialog fragment for renaming the local Bluetooth device. 51 */ 52 public final class BluetoothNameDialogFragment extends InstrumentedDialogFragment 53 implements TextWatcher { 54 private static final int BLUETOOTH_NAME_MAX_LENGTH_BYTES = 248; 55 56 private AlertDialog mAlertDialog; 57 private Button mOkButton; 58 59 // accessed from inner class (not private to avoid thunks) 60 static final String TAG = "BluetoothNameDialogFragment"; 61 final LocalBluetoothAdapter mLocalAdapter; 62 EditText mDeviceNameView; 63 64 // This flag is set when the name is updated by code, to distinguish from user changes 65 private boolean mDeviceNameUpdated; 66 67 // This flag is set when the user edits the name (preserved on rotation) 68 private boolean mDeviceNameEdited; 69 70 // Key to save the edited name and edit status for restoring after rotation 71 private static final String KEY_NAME = "device_name"; 72 private static final String KEY_NAME_EDITED = "device_name_edited"; 73 74 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 75 @Override 76 public void onReceive(Context context, Intent intent) { 77 String action = intent.getAction(); 78 if (action.equals(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED)) { 79 updateDeviceName(); 80 } else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED) && 81 (intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR) == 82 BluetoothAdapter.STATE_ON)) { 83 updateDeviceName(); 84 } 85 } 86 }; 87 BluetoothNameDialogFragment()88 public BluetoothNameDialogFragment() { 89 LocalBluetoothManager localManager = Utils.getLocalBtManager(getActivity()); 90 mLocalAdapter = localManager.getBluetoothAdapter(); 91 } 92 93 @Override getMetricsCategory()94 public int getMetricsCategory() { 95 return MetricsProto.MetricsEvent.DIALOG_BLUETOOTH_RENAME; 96 } 97 98 @Override onCreateDialog(Bundle savedInstanceState)99 public Dialog onCreateDialog(Bundle savedInstanceState) { 100 String deviceName = mLocalAdapter.getName(); 101 if (savedInstanceState != null) { 102 deviceName = savedInstanceState.getString(KEY_NAME, deviceName); 103 mDeviceNameEdited = savedInstanceState.getBoolean(KEY_NAME_EDITED, false); 104 } 105 mAlertDialog = new AlertDialog.Builder(getActivity()) 106 .setTitle(R.string.bluetooth_rename_device) 107 .setView(createDialogView(deviceName)) 108 .setPositiveButton(R.string.bluetooth_rename_button, 109 new DialogInterface.OnClickListener() { 110 public void onClick(DialogInterface dialog, int which) { 111 String deviceName = mDeviceNameView.getText().toString(); 112 setDeviceName(deviceName); 113 } 114 }) 115 .setNegativeButton(android.R.string.cancel, null) 116 .create(); 117 mAlertDialog.getWindow().setSoftInputMode( 118 WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); 119 120 return mAlertDialog; 121 } 122 setDeviceName(String deviceName)123 private void setDeviceName(String deviceName) { 124 Log.d(TAG, "Setting device name to " + deviceName); 125 mLocalAdapter.setName(deviceName); 126 } 127 128 @Override onSaveInstanceState(Bundle outState)129 public void onSaveInstanceState(Bundle outState) { 130 outState.putString(KEY_NAME, mDeviceNameView.getText().toString()); 131 outState.putBoolean(KEY_NAME_EDITED, mDeviceNameEdited); 132 } 133 createDialogView(String deviceName)134 private View createDialogView(String deviceName) { 135 final LayoutInflater layoutInflater = (LayoutInflater)getActivity() 136 .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 137 View view = layoutInflater.inflate(R.layout.dialog_edittext, null); 138 mDeviceNameView = (EditText) view.findViewById(R.id.edittext); 139 mDeviceNameView.setFilters(new InputFilter[] { 140 new Utf8ByteLengthFilter(BLUETOOTH_NAME_MAX_LENGTH_BYTES) 141 }); 142 mDeviceNameView.setText(deviceName); // set initial value before adding listener 143 mDeviceNameView.addTextChangedListener(this); 144 mDeviceNameView.setOnEditorActionListener(new TextView.OnEditorActionListener() { 145 @Override 146 public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { 147 if (actionId == EditorInfo.IME_ACTION_DONE) { 148 setDeviceName(v.getText().toString()); 149 mAlertDialog.dismiss(); 150 return true; // action handled 151 } else { 152 return false; // not handled 153 } 154 } 155 }); 156 return view; 157 } 158 159 @Override onDestroy()160 public void onDestroy() { 161 super.onDestroy(); 162 mAlertDialog = null; 163 mDeviceNameView = null; 164 mOkButton = null; 165 } 166 167 @Override onResume()168 public void onResume() { 169 super.onResume(); 170 if (mOkButton == null) { 171 mOkButton = mAlertDialog.getButton(DialogInterface.BUTTON_POSITIVE); 172 mOkButton.setEnabled(mDeviceNameEdited); // Ok button enabled after user edits 173 } 174 IntentFilter filter = new IntentFilter(); 175 filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); 176 filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED); 177 getActivity().registerReceiver(mReceiver, filter); 178 } 179 180 @Override onPause()181 public void onPause() { 182 super.onPause(); 183 getActivity().unregisterReceiver(mReceiver); 184 } 185 updateDeviceName()186 void updateDeviceName() { 187 if (mLocalAdapter != null && mLocalAdapter.isEnabled()) { 188 mDeviceNameUpdated = true; 189 mDeviceNameEdited = false; 190 mDeviceNameView.setText(mLocalAdapter.getName()); 191 } 192 } 193 afterTextChanged(Editable s)194 public void afterTextChanged(Editable s) { 195 if (mDeviceNameUpdated) { 196 // Device name changed by code; disable Ok button until edited by user 197 mDeviceNameUpdated = false; 198 mOkButton.setEnabled(false); 199 } else { 200 mDeviceNameEdited = true; 201 if (mOkButton != null) { 202 mOkButton.setEnabled(s.toString().trim().length() != 0); 203 } 204 } 205 } 206 onConfigurationChanged(Configuration newConfig, CharSequence s)207 public void onConfigurationChanged(Configuration newConfig, CharSequence s) { 208 super.onConfigurationChanged(newConfig); 209 if (mOkButton != null) { 210 mOkButton.setEnabled(s.length() != 0 && !(s.toString().trim().isEmpty())); 211 } 212 } 213 214 /* Not used */ beforeTextChanged(CharSequence s, int start, int count, int after)215 public void beforeTextChanged(CharSequence s, int start, int count, int after) { 216 } 217 218 /* Not used */ onTextChanged(CharSequence s, int start, int before, int count)219 public void onTextChanged(CharSequence s, int start, int before, int count) { 220 } 221 } 222