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 9c90b20..7c8cb6e
@@ -20,17 +20,28 @@ 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.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;
 
 /**
@@ -40,16 +51,60 @@ import com.android.settings.R;
 public final class BluetoothSettings extends DeviceListPreferenceFragment {
     private static final String TAG = "BluetoothSettings";
 
-    private static final int MENU_ID_MAKE_DISCOVERABLE = Menu.FIRST;
-    private static final int MENU_ID_SCAN = Menu.FIRST + 1;
-    private static final int MENU_ID_ADVANCED = Menu.FIRST + 2;
+    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";
 
     private BluetoothEnabler mBluetoothEnabler;
 
-    /** Initialize the filter to show bonded devices only. */
-    //public BluetoothSettings() {
-    //    super(BluetoothDeviceFilter.BONDED_DEVICE_FILTER);
-    //}
+    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() {
+        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() {
@@ -76,89 +131,92 @@ public final class BluetoothSettings extends DeviceListPreferenceFragment {
 
         mBluetoothEnabler = new BluetoothEnabler(activity, actionBarSwitch);
 
-        if (mLocalAdapter != null && mLocalAdapter.isEnabled()) {
-            activity.getActionBar().setSubtitle(mLocalAdapter.getName());
-        }
-
-        // TODO activity.setTheme(android.R.style.Theme_Holo_SplitActionBarWhenNarrow);
-
         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();
 
-        mBluetoothEnabler.resume();
-
-        updateContent(mLocalAdapter.getBluetoothState());
+        if (mDiscoverableEnabler != null) {
+            mDiscoverableEnabler.resume();
+        }
+        getActivity().registerReceiver(mReceiver, mIntentFilter);
+        if (mLocalAdapter != null) {
+            updateContent(mLocalAdapter.getBluetoothState(), mActivityStarted);
+        }
     }
 
     @Override
     public void onPause() {
         super.onPause();
-
-        mBluetoothEnabler.pause();
+        if (mBluetoothEnabler != null) {
+            mBluetoothEnabler.pause();
+        }
+        getActivity().unregisterReceiver(mReceiver);
+        if (mDiscoverableEnabler != null) {
+            mDiscoverableEnabler.pause();
+        }
     }
 
     @Override
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        if (mLocalAdapter == null) return;
         boolean bluetoothIsEnabled = mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_ON;
-        menu.add(Menu.NONE, MENU_ID_MAKE_DISCOVERABLE, 0, R.string.bluetooth_visibility)
-                .setEnabled(bluetoothIsEnabled);
-        menu.add(Menu.NONE, MENU_ID_SCAN, 0, R.string.bluetooth_preference_find_nearby_title)
-                .setIcon(R.drawable.ic_menu_scan_network).setEnabled(bluetoothIsEnabled);
-        menu.add(Menu.NONE, MENU_ID_ADVANCED, 0, R.string.bluetooth_menu_advanced)
-                .setIcon(android.R.drawable.ic_menu_manage);
+        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);
     }
 
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         switch (item.getItemId()) {
-            case MENU_ID_MAKE_DISCOVERABLE:
-                // TODO
-//                if (mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_ON) {
-//                    onAddNetworkPressed();
-//                }
-                return true;
             case MENU_ID_SCAN:
                 if (mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_ON) {
-                    mLocalAdapter.startScanning(true);
+                    startScanning();
                 }
                 return true;
-            case MENU_ID_ADVANCED:
-                if (getActivity() instanceof PreferenceActivity) {
-                    ((PreferenceActivity) getActivity()).startPreferencePanel(
-                            AdvancedBluetoothSettings.class.getCanonicalName(),
-                            null,
-                            R.string.bluetooth_advanced_titlebar, null,
-                            this, 0);
-                } else {
-                    startFragment(this, AdvancedBluetoothSettings.class.getCanonicalName(), -1, null);
-                }
+
+            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 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);
-            }
+    private void startScanning() {
+        if (!mAvailableDevicesCategoryIsPresent) {
+            getPreferenceScreen().addPreference(mAvailableDevicesCategory);
         }
-    };
+        mLocalAdapter.startScanning(true);
+    }
 
     @Override
     void onDevicePreferenceClick(BluetoothDevicePreference btPreference) {
@@ -166,31 +224,95 @@ public final class BluetoothSettings extends DeviceListPreferenceFragment {
         super.onDevicePreferenceClick(btPreference);
     }
 
-    @Override
-    public void onBluetoothStateChanged(int bluetoothState) {
-        super.onBluetoothStateChanged(bluetoothState);
-        updateContent(bluetoothState);
+    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) {
+    private void updateContent(int bluetoothState, boolean scanState) {
         final PreferenceScreen preferenceScreen = getPreferenceScreen();
-        getActivity().invalidateOptionsMenu();
         int messageId = 0;
 
         switch (bluetoothState) {
             case BluetoothAdapter.STATE_ON:
                 preferenceScreen.removeAll();
-                // Repopulate (which isn't too bad since it's cached in the settings bluetooth manager)
-                addDevices();
-                mLocalAdapter.startScanning(false);
-                return;
+                preferenceScreen.setOrderingAsAdded(true);
+                mDevicePreferenceMap.clear();
 
-            case BluetoothAdapter.STATE_TURNING_OFF:
-                int preferenceCount = preferenceScreen.getPreferenceCount();
-                for (int i = 0; i < preferenceCount; i++) {
-                    preferenceScreen.getPreference(i).setEnabled(false);
+                // 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();
                 }
-                return;
+                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;
@@ -201,24 +323,48 @@ public final class BluetoothSettings extends DeviceListPreferenceFragment {
                 break;
         }
 
+        setDeviceListGroup(preferenceScreen);
         removeAllDevices();
-        // TODO: from xml, add top padding. Same as in wifi
-        Preference emptyListPreference = new Preference(getActivity());
-        emptyListPreference.setTitle(messageId);
-        preferenceScreen.addPreference(emptyListPreference);
+        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) {
-        if (bondState == BluetoothDevice.BOND_BONDED) {
-            // add to "Paired devices" list after remote-initiated pairing
-            if (mDevicePreferenceMap.get(cachedDevice) == null) {
-                createDevicePreference(cachedDevice);
+        setDeviceListGroup(getPreferenceScreen());
+        removeAllDevices();
+        updateContent(mLocalAdapter.getBluetoothState(), false);
+    }
+
+    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.
@@ -226,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);
+        }
     }
 }