1 /* 2 * Copyright (C) 2017 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 package com.android.car.settings.bluetooth; 17 18 import android.bluetooth.BluetoothAdapter; 19 import android.content.BroadcastReceiver; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.IntentFilter; 23 import android.os.Bundle; 24 import android.support.v4.widget.SwipeRefreshLayout; 25 import android.view.View; 26 import android.widget.ProgressBar; 27 import android.widget.Switch; 28 import android.widget.TextView; 29 import android.widget.ViewSwitcher; 30 31 import androidx.car.widget.PagedListView; 32 33 import com.android.car.settings.R; 34 import com.android.car.settings.common.BaseFragment; 35 import com.android.car.settings.common.Logger; 36 import com.android.settingslib.bluetooth.BluetoothCallback; 37 import com.android.settingslib.bluetooth.CachedBluetoothDevice; 38 import com.android.settingslib.bluetooth.LocalBluetoothAdapter; 39 import com.android.settingslib.bluetooth.LocalBluetoothManager; 40 41 /** 42 * Hosts Bluetooth related preferences. 43 */ 44 public class BluetoothSettingsFragment extends BaseFragment implements BluetoothCallback { 45 private static final Logger LOG = new Logger(BluetoothSettingsFragment.class); 46 47 private SwipeRefreshLayout mSwipeRefreshLayout; 48 private Switch mBluetoothSwitch; 49 private ProgressBar mProgressBar; 50 private PagedListView mDeviceListView; 51 private ViewSwitcher mViewSwitcher; 52 private TextView mMessageView; 53 private BluetoothDeviceListAdapter mDeviceAdapter; 54 private LocalBluetoothAdapter mLocalAdapter; 55 private LocalBluetoothManager mLocalManager; 56 57 private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 58 @Override 59 public void onReceive(Context context, Intent intent) { 60 if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(intent.getAction())) { 61 setProgressBarVisible(true); 62 mBluetoothSwitch.setChecked(true); 63 if (mViewSwitcher.getCurrentView() != mSwipeRefreshLayout) { 64 mViewSwitcher.showPrevious(); 65 } 66 } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(intent.getAction())) { 67 setProgressBarVisible(false); 68 } 69 } 70 }; 71 72 public static BluetoothSettingsFragment getInstance() { 73 BluetoothSettingsFragment bluetoothSettingsFragment = new BluetoothSettingsFragment(); 74 Bundle bundle = BaseFragment.getBundle(); 75 bundle.putInt(EXTRA_TITLE_ID, R.string.bluetooth_settings); 76 bundle.putInt(EXTRA_LAYOUT, R.layout.bluetooth_list); 77 bundle.putInt(EXTRA_ACTION_BAR_LAYOUT, R.layout.action_bar_with_toggle); 78 bluetoothSettingsFragment.setArguments(bundle); 79 return bluetoothSettingsFragment; 80 } 81 82 @Override 83 public void onActivityCreated(Bundle savedInstanceState) { 84 super.onActivityCreated(savedInstanceState); 85 mBluetoothSwitch = getActivity().findViewById(R.id.toggle_switch); 86 mSwipeRefreshLayout = getActivity().findViewById(R.id.swiperefresh); 87 mSwipeRefreshLayout.setSize(SwipeRefreshLayout.LARGE); 88 mSwipeRefreshLayout.setOnRefreshListener( 89 new SwipeRefreshLayout.OnRefreshListener() { 90 @Override 91 public void onRefresh() { 92 mSwipeRefreshLayout.setRefreshing(false); 93 if (mLocalAdapter.isDiscovering()) { 94 mLocalAdapter.cancelDiscovery(); 95 } 96 mDeviceAdapter.reset(); 97 } 98 } 99 ); 100 101 mBluetoothSwitch.setOnCheckedChangeListener((v, isChecked) -> { 102 if (mBluetoothSwitch.isChecked()) { 103 // bt scan was turned on at state listener, when state is on. 104 mLocalAdapter.setBluetoothEnabled(true); 105 } else { 106 mLocalAdapter.stopScanning(); 107 mLocalAdapter.setBluetoothEnabled(false); 108 } 109 }); 110 111 mProgressBar = getView().findViewById(R.id.bt_search_progress); 112 mDeviceListView = getView().findViewById(R.id.list); 113 mViewSwitcher = getView().findViewById(R.id.view_switcher); 114 mMessageView = getView().findViewById(R.id.bt_message); 115 116 mLocalManager = 117 LocalBluetoothManager.getInstance(getContext(), /* onInitCallback= */ null); 118 if (mLocalManager == null) { 119 LOG.e("Bluetooth is not supported on this device"); 120 return; 121 } 122 mLocalAdapter = mLocalManager.getBluetoothAdapter(); 123 } 124 125 @Override 126 public void onStart() { 127 super.onStart(); 128 if (mLocalManager == null) { 129 return; 130 } 131 IntentFilter filter = new IntentFilter(); 132 filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED); 133 filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); 134 getActivity().registerReceiver(mBroadcastReceiver, filter); 135 136 mLocalManager.setForegroundActivity(getActivity()); 137 mLocalManager.getEventManager().registerCallback(this); 138 mBluetoothSwitch.setChecked(mLocalAdapter.isEnabled()); 139 if (mLocalAdapter.isEnabled()) { 140 setProgressBarVisible(true); 141 mLocalAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE); 142 mLocalAdapter.startScanning(true); 143 if (mViewSwitcher.getCurrentView() != mSwipeRefreshLayout) { 144 mViewSwitcher.showPrevious(); 145 } 146 } else { 147 setProgressBarVisible(false); 148 if (mViewSwitcher.getCurrentView() != mMessageView) { 149 mViewSwitcher.showNext(); 150 } 151 } 152 mDeviceAdapter = new BluetoothDeviceListAdapter( 153 getContext() , mLocalManager, getFragmentController()); 154 mDeviceListView.setAdapter(mDeviceAdapter); 155 mDeviceAdapter.start(); 156 } 157 158 @Override 159 public void onStop() { 160 super.onStop(); 161 if (mLocalManager == null) { 162 return; 163 } 164 getActivity().unregisterReceiver(mBroadcastReceiver); 165 mDeviceAdapter.stop(); 166 mLocalAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE); 167 mLocalManager.setForegroundActivity(null); 168 mLocalAdapter.stopScanning(); 169 mLocalManager.getEventManager().unregisterCallback(this); 170 } 171 172 @Override 173 public void onBluetoothStateChanged(int bluetoothState) { 174 switch (bluetoothState) { 175 case BluetoothAdapter.STATE_OFF: 176 setProgressBarVisible(false); 177 mBluetoothSwitch.setChecked(false); 178 if (mViewSwitcher.getCurrentView() != mMessageView) { 179 mViewSwitcher.showNext(); 180 } 181 break; 182 case BluetoothAdapter.STATE_ON: 183 case BluetoothAdapter.STATE_TURNING_ON: 184 setProgressBarVisible(true); 185 mBluetoothSwitch.setChecked(true); 186 if (mViewSwitcher.getCurrentView() != mSwipeRefreshLayout) { 187 mViewSwitcher.showPrevious(); 188 } 189 break; 190 case BluetoothAdapter.STATE_TURNING_OFF: 191 setProgressBarVisible(true); 192 break; 193 } 194 } 195 196 @Override 197 public void onScanningStateChanged(boolean started) { 198 if (!started) { 199 setProgressBarVisible(false); 200 } 201 } 202 203 @Override 204 public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) { 205 // no-op 206 } 207 208 @Override 209 public void onDeviceAdded(CachedBluetoothDevice cachedDevice) { 210 // no-op 211 } 212 213 @Override 214 public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) { 215 // no-op 216 } 217 218 @Override 219 public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { 220 // no-op 221 } 222 223 @Override 224 public void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile) { 225 // no-op 226 } 227 228 @Override 229 public void onAudioModeChanged() { 230 // no-op 231 } 232 233 private void setProgressBarVisible(boolean visible) { 234 if (mProgressBar != null) { 235 mProgressBar.setVisibility(visible ? View.VISIBLE : View.GONE); 236 } 237 } 238 } 239