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