OSDN Git Service

Don't crash if there's no bluetooth functionality (such as in an emulator) do not...
[android-x86/packages-apps-Settings.git] / src / com / android / settings / bluetooth / BluetoothSettings.java
old mode 100644 (file)
new mode 100755 (executable)
index 5e4e130..7c8cb6e
 
 package com.android.settings.bluetooth;
 
+import android.app.ActionBar;
+import android.app.Activity;
+import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
+import android.content.BroadcastReceiver;
+import android.content.Context;
 import android.content.Intent;
-import android.preference.CheckBoxPreference;
-import android.preference.ListPreference;
+import android.content.IntentFilter;
+import android.os.Bundle;
 import android.preference.Preference;
 import android.preference.PreferenceActivity;
+import android.preference.PreferenceCategory;
+import android.preference.PreferenceGroup;
 import android.preference.PreferenceScreen;
 import android.util.Log;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
 import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Switch;
+import android.widget.TextView;
 
+import com.android.settings.ProgressCategory;
 import com.android.settings.R;
 
 /**
@@ -35,107 +51,320 @@ import com.android.settings.R;
 public final class BluetoothSettings extends DeviceListPreferenceFragment {
     private static final String TAG = "BluetoothSettings";
 
-    private static final String KEY_BT_CHECKBOX = "bt_checkbox";
-    private static final String KEY_BT_DISCOVERABLE = "bt_discoverable";
-    private static final String KEY_BT_DISCOVERABLE_TIMEOUT = "bt_discoverable_timeout";
-    private static final String KEY_BT_NAME = "bt_name";
-    private static final String KEY_BT_SHOW_RECEIVED = "bt_show_received_files";
-
-    private BluetoothEnabler mEnabler;
-    private BluetoothDiscoverableEnabler mDiscoverableEnabler;
-    private BluetoothNamePreference mNamePreference;
+    private static final int MENU_ID_SCAN = Menu.FIRST;
+    private static final int MENU_ID_RENAME_DEVICE = Menu.FIRST + 1;
+    private static final int MENU_ID_VISIBILITY_TIMEOUT = Menu.FIRST + 2;
+    private static final int MENU_ID_SHOW_RECEIVED = Menu.FIRST + 3;
 
     /* Private intent to show the list of received files */
     private static final String BTOPP_ACTION_OPEN_RECEIVED_FILES =
             "android.btopp.intent.action.OPEN_RECEIVED_FILES";
 
-    /** Initialize the filter to show bonded devices only. */
+    private BluetoothEnabler mBluetoothEnabler;
+
+    private BluetoothDiscoverableEnabler mDiscoverableEnabler;
+
+    private PreferenceGroup mPairedDevicesCategory;
+
+    private PreferenceGroup mAvailableDevicesCategory;
+    private boolean mAvailableDevicesCategoryIsPresent;
+    private boolean mActivityStarted;
+
+    private TextView mEmptyView;
+
+    private final IntentFilter mIntentFilter;
+
+    // accessed from inner class (not private to avoid thunks)
+    Preference mMyDevicePreference;
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (action.equals(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED)) {
+                updateDeviceName();
+            }
+        }
+
+        private void updateDeviceName() {
+            if (mLocalAdapter.isEnabled() && mMyDevicePreference != null) {
+                mMyDevicePreference.setTitle(mLocalAdapter.getName());
+            }
+        }
+    };
+
     public BluetoothSettings() {
-        super(BluetoothDeviceFilter.BONDED_DEVICE_FILTER);
+        mIntentFilter = new IntentFilter(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
+    }
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        mActivityStarted = (savedInstanceState == null);    // don't auto start scan after rotation
+
+        mEmptyView = (TextView) getView().findViewById(android.R.id.empty);
+        getListView().setEmptyView(mEmptyView);
     }
 
     @Override
     void addPreferencesForActivity() {
         addPreferencesFromResource(R.xml.bluetooth_settings);
 
-        mEnabler = new BluetoothEnabler(getActivity(),
-                (CheckBoxPreference) findPreference(KEY_BT_CHECKBOX));
+        Activity activity = getActivity();
+
+        Switch actionBarSwitch = new Switch(activity);
+
+        if (activity instanceof PreferenceActivity) {
+            PreferenceActivity preferenceActivity = (PreferenceActivity) activity;
+            if (preferenceActivity.onIsHidingHeaders() || !preferenceActivity.onIsMultiPane()) {
+                final int padding = activity.getResources().getDimensionPixelSize(
+                        R.dimen.action_bar_switch_padding);
+                actionBarSwitch.setPadding(0, 0, padding, 0);
+                activity.getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
+                        ActionBar.DISPLAY_SHOW_CUSTOM);
+                activity.getActionBar().setCustomView(actionBarSwitch, new ActionBar.LayoutParams(
+                        ActionBar.LayoutParams.WRAP_CONTENT,
+                        ActionBar.LayoutParams.WRAP_CONTENT,
+                        Gravity.CENTER_VERTICAL | Gravity.RIGHT));
+            }
+        }
 
-        mDiscoverableEnabler = new BluetoothDiscoverableEnabler(getActivity(),
-                mLocalAdapter,
-                (CheckBoxPreference) findPreference(KEY_BT_DISCOVERABLE),
-                    (ListPreference) findPreference(KEY_BT_DISCOVERABLE_TIMEOUT));
+        mBluetoothEnabler = new BluetoothEnabler(activity, actionBarSwitch);
 
-        mNamePreference = (BluetoothNamePreference) findPreference(KEY_BT_NAME);
+        setHasOptionsMenu(true);
     }
 
     @Override
     public void onResume() {
+        // resume BluetoothEnabler before calling super.onResume() so we don't get
+        // any onDeviceAdded() callbacks before setting up view in updateContent()
+        if (mBluetoothEnabler != null) {
+            mBluetoothEnabler.resume();
+        }
         super.onResume();
 
-        // Repopulate (which isn't too bad since it's cached in the settings
-        // bluetooth manager)
-        addDevices();
-
-        mEnabler.resume();
-        mDiscoverableEnabler.resume();
-        mNamePreference.resume();
+        if (mDiscoverableEnabler != null) {
+            mDiscoverableEnabler.resume();
+        }
+        getActivity().registerReceiver(mReceiver, mIntentFilter);
+        if (mLocalAdapter != null) {
+            updateContent(mLocalAdapter.getBluetoothState(), mActivityStarted);
+        }
     }
 
     @Override
     public void onPause() {
         super.onPause();
+        if (mBluetoothEnabler != null) {
+            mBluetoothEnabler.pause();
+        }
+        getActivity().unregisterReceiver(mReceiver);
+        if (mDiscoverableEnabler != null) {
+            mDiscoverableEnabler.pause();
+        }
+    }
 
-        mNamePreference.pause();
-        mDiscoverableEnabler.pause();
-        mEnabler.pause();
+    @Override
+    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        if (mLocalAdapter == null) return;
+        boolean bluetoothIsEnabled = mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_ON;
+        boolean isDiscovering = mLocalAdapter.isDiscovering();
+        int textId = isDiscovering ? R.string.bluetooth_searching_for_devices :
+            R.string.bluetooth_search_for_devices;
+        menu.add(Menu.NONE, MENU_ID_SCAN, 0, textId)
+                .setEnabled(bluetoothIsEnabled && !isDiscovering)
+                .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+        menu.add(Menu.NONE, MENU_ID_RENAME_DEVICE, 0, R.string.bluetooth_rename_device)
+                .setEnabled(bluetoothIsEnabled)
+                .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+        menu.add(Menu.NONE, MENU_ID_VISIBILITY_TIMEOUT, 0, R.string.bluetooth_visibility_timeout)
+                .setEnabled(bluetoothIsEnabled)
+                .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+        menu.add(Menu.NONE, MENU_ID_SHOW_RECEIVED, 0, R.string.bluetooth_show_received_files)
+                .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
     }
 
-    private final View.OnClickListener mListener = new View.OnClickListener() {
-        public void onClick(View v) {
-            // User clicked on advanced options icon for a device in the list
-            if (v.getTag() instanceof CachedBluetoothDevice) {
-                CachedBluetoothDevice
-                        device = (CachedBluetoothDevice) v.getTag();
-
-                Preference pref = new Preference(getActivity());
-                pref.setTitle(device.getName());
-                pref.setFragment(DeviceProfilesSettings.class.getName());
-                pref.getExtras().putParcelable(DeviceProfilesSettings.EXTRA_DEVICE,
-                        device.getDevice());
-                ((PreferenceActivity) getActivity())
-                        .onPreferenceStartFragment(BluetoothSettings.this,
-                                pref);
-            } else {
-                Log.w(TAG, "onClick() called for other View: " + v);
-            }
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case MENU_ID_SCAN:
+                if (mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_ON) {
+                    startScanning();
+                }
+                return true;
+
+            case MENU_ID_RENAME_DEVICE:
+                new BluetoothNameDialogFragment().show(
+                        getFragmentManager(), "rename device");
+                return true;
+
+            case MENU_ID_VISIBILITY_TIMEOUT:
+                new BluetoothVisibilityTimeoutFragment().show(
+                        getFragmentManager(), "visibility timeout");
+                return true;
+
+            case MENU_ID_SHOW_RECEIVED:
+                Intent intent = new Intent(BTOPP_ACTION_OPEN_RECEIVED_FILES);
+                getActivity().sendBroadcast(intent);
+                return true;
         }
-    };
+        return super.onOptionsItemSelected(item);
+    }
+
+    private void startScanning() {
+        if (!mAvailableDevicesCategoryIsPresent) {
+            getPreferenceScreen().addPreference(mAvailableDevicesCategory);
+        }
+        mLocalAdapter.startScanning(true);
+    }
 
     @Override
-    public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
-            Preference preference) {
-        if (KEY_BT_SHOW_RECEIVED.equals(preference.getKey())) {
-            Intent intent = new Intent(BTOPP_ACTION_OPEN_RECEIVED_FILES);
-            getActivity().sendBroadcast(intent);
-            return true;
+    void onDevicePreferenceClick(BluetoothDevicePreference btPreference) {
+        mLocalAdapter.stopScanning();
+        super.onDevicePreferenceClick(btPreference);
+    }
+
+    private void addDeviceCategory(PreferenceGroup preferenceGroup, int titleId,
+            BluetoothDeviceFilter.Filter filter) {
+        preferenceGroup.setTitle(titleId);
+        getPreferenceScreen().addPreference(preferenceGroup);
+        setFilter(filter);
+        setDeviceListGroup(preferenceGroup);
+        addCachedDevices();
+        preferenceGroup.setEnabled(true);
+    }
+
+    private void updateContent(int bluetoothState, boolean scanState) {
+        final PreferenceScreen preferenceScreen = getPreferenceScreen();
+        int messageId = 0;
+
+        switch (bluetoothState) {
+            case BluetoothAdapter.STATE_ON:
+                preferenceScreen.removeAll();
+                preferenceScreen.setOrderingAsAdded(true);
+                mDevicePreferenceMap.clear();
+
+                // This device
+                if (mMyDevicePreference == null) {
+                    mMyDevicePreference = new Preference(getActivity());
+                }
+                mMyDevicePreference.setTitle(mLocalAdapter.getName());
+                if (getResources().getBoolean(com.android.internal.R.bool.config_voice_capable)) {
+                    mMyDevicePreference.setIcon(R.drawable.ic_bt_cellphone);    // for phones
+                } else {
+                    mMyDevicePreference.setIcon(R.drawable.ic_bt_laptop);   // for tablets, etc.
+                }
+                mMyDevicePreference.setPersistent(false);
+                mMyDevicePreference.setEnabled(true);
+                preferenceScreen.addPreference(mMyDevicePreference);
+
+                if (mDiscoverableEnabler == null) {
+                    mDiscoverableEnabler = new BluetoothDiscoverableEnabler(getActivity(),
+                            mLocalAdapter, mMyDevicePreference);
+                    mDiscoverableEnabler.resume();
+                    LocalBluetoothManager.getInstance(getActivity()).setDiscoverableEnabler(
+                            mDiscoverableEnabler);
+                }
+
+                // Paired devices category
+                if (mPairedDevicesCategory == null) {
+                    mPairedDevicesCategory = new PreferenceCategory(getActivity());
+                } else {
+                    mPairedDevicesCategory.removeAll();
+                }
+                addDeviceCategory(mPairedDevicesCategory,
+                        R.string.bluetooth_preference_paired_devices,
+                        BluetoothDeviceFilter.BONDED_DEVICE_FILTER);
+                int numberOfPairedDevices = mPairedDevicesCategory.getPreferenceCount();
+
+                mDiscoverableEnabler.setNumberOfPairedDevices(numberOfPairedDevices);
+
+                // Available devices category
+                if (mAvailableDevicesCategory == null) {
+                    mAvailableDevicesCategory = new ProgressCategory(getActivity(), null);
+                } else {
+                    mAvailableDevicesCategory.removeAll();
+                }
+                addDeviceCategory(mAvailableDevicesCategory,
+                        R.string.bluetooth_preference_found_devices,
+                        BluetoothDeviceFilter.UNBONDED_DEVICE_FILTER);
+                int numberOfAvailableDevices = mAvailableDevicesCategory.getPreferenceCount();
+                mAvailableDevicesCategoryIsPresent = true;
+
+                if (numberOfAvailableDevices == 0) {
+                    preferenceScreen.removePreference(mAvailableDevicesCategory);
+                    mAvailableDevicesCategoryIsPresent = false;
+                }
+
+                if (numberOfPairedDevices == 0) {
+                    preferenceScreen.removePreference(mPairedDevicesCategory);
+                    if (scanState == true) {
+                        mActivityStarted = false;
+                        startScanning();
+                    } else {
+                        if (!mAvailableDevicesCategoryIsPresent) {
+                            getPreferenceScreen().addPreference(mAvailableDevicesCategory);
+                        }
+                    }
+                }
+                getActivity().invalidateOptionsMenu();
+                return; // not break
+
+            case BluetoothAdapter.STATE_TURNING_OFF:
+                messageId = R.string.bluetooth_turning_off;
+                break;
+
+            case BluetoothAdapter.STATE_OFF:
+                messageId = R.string.bluetooth_empty_list_bluetooth_off;
+                break;
+
+            case BluetoothAdapter.STATE_TURNING_ON:
+                messageId = R.string.bluetooth_turning_on;
+                break;
         }
 
-        return super.onPreferenceTreeClick(preferenceScreen, preference);
+        setDeviceListGroup(preferenceScreen);
+        removeAllDevices();
+        mEmptyView.setText(messageId);
+        getActivity().invalidateOptionsMenu();
+    }
+
+    @Override
+    public void onBluetoothStateChanged(int bluetoothState) {
+        super.onBluetoothStateChanged(bluetoothState);
+        updateContent(bluetoothState, true);
+    }
+
+    @Override
+    public void onScanningStateChanged(boolean started) {
+        super.onScanningStateChanged(started);
+        // Update options' enabled state
+        getActivity().invalidateOptionsMenu();
+    }
+
+    public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
+        setDeviceListGroup(getPreferenceScreen());
+        removeAllDevices();
+        updateContent(mLocalAdapter.getBluetoothState(), false);
     }
 
-    public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice,
-            int bondState) {
-        if (bondState == BluetoothDevice.BOND_BONDED) {
-            // add to "Paired devices" list after remote-initiated pairing
-            if (mDevicePreferenceMap.get(cachedDevice) == null) {
-                createDevicePreference(cachedDevice);
+    private final View.OnClickListener mDeviceProfilesListener = new View.OnClickListener() {
+        public void onClick(View v) {
+            // User clicked on advanced options icon for a device in the list
+            if (v.getTag() instanceof CachedBluetoothDevice) {
+                CachedBluetoothDevice device = (CachedBluetoothDevice) v.getTag();
+
+                Bundle args = new Bundle(1);
+                args.putParcelable(DeviceProfilesSettings.EXTRA_DEVICE, device.getDevice());
+
+                ((PreferenceActivity) getActivity()).startPreferencePanel(
+                        DeviceProfilesSettings.class.getName(), args,
+                        R.string.bluetooth_device_advanced_title, null, null, 0);
+            } else {
+                Log.w(TAG, "onClick() called for other View: " + v); // TODO remove
             }
-        } else if (bondState == BluetoothDevice.BOND_NONE) {
-            // remove unpaired device from paired devices list
-            onDeviceDeleted(cachedDevice);
         }
-    }
+    };
 
     /**
      * Add a listener, which enables the advanced settings icon.
@@ -143,6 +372,10 @@ public final class BluetoothSettings extends DeviceListPreferenceFragment {
      */
     @Override
     void initDevicePreference(BluetoothDevicePreference preference) {
-        preference.setOnSettingsClickListener(mListener);
+        CachedBluetoothDevice cachedDevice = preference.getCachedDevice();
+        if (cachedDevice.getBondState() == BluetoothDevice.BOND_BONDED) {
+            // Only paired device have an associated advanced settings screen
+            preference.setOnSettingsClickListener(mDeviceProfilesListener);
+        }
     }
 }