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