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 
17 package com.android.car.settings.bluetooth;
18 
19 import static android.os.UserManager.DISALLOW_BLUETOOTH;
20 
21 import android.bluetooth.BluetoothAdapter;
22 import android.content.BroadcastReceiver;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.IntentFilter;
26 import android.os.Bundle;
27 import android.os.UserManager;
28 import android.provider.Settings;
29 
30 import androidx.annotation.XmlRes;
31 
32 import com.android.car.settings.R;
33 import com.android.car.settings.common.SettingsFragment;
34 import com.android.car.settings.search.CarBaseSearchIndexProvider;
35 import com.android.car.ui.toolbar.MenuItem;
36 import com.android.settingslib.bluetooth.LocalBluetoothManager;
37 import com.android.settingslib.search.SearchIndexable;
38 
39 import java.util.Collections;
40 import java.util.List;
41 
42 /**
43  * Main page for Bluetooth settings. It manages the power switch for the Bluetooth adapter. It also
44  * displays paired devices and the entry point for device pairing.
45  */
46 @SearchIndexable
47 public class BluetoothSettingsFragment extends SettingsFragment {
48 
49     private final BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
50     private final IntentFilter mIntentFilter = new IntentFilter(
51             BluetoothAdapter.ACTION_STATE_CHANGED);
52     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
53         @Override
54         public void onReceive(Context context, Intent intent) {
55             int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
56             handleStateChanged(state);
57         }
58     };
59     private final MenuItem.OnClickListener mBluetoothSwitchListener = item -> {
60         item.setEnabled(false);
61         if (item.isChecked()) {
62             mBluetoothAdapter.enable();
63         } else {
64             mBluetoothAdapter.disable();
65         }
66     };
67 
68     private UserManager mUserManager;
69     private LocalBluetoothManager mLocalBluetoothManager;
70     private MenuItem mBluetoothSwitch;
71 
72     @Override
73     @XmlRes
getPreferenceScreenResId()74     protected int getPreferenceScreenResId() {
75         return R.xml.bluetooth_settings_fragment;
76     }
77 
78     @Override
getToolbarMenuItems()79     protected List<MenuItem> getToolbarMenuItems() {
80         return Collections.singletonList(mBluetoothSwitch);
81     }
82 
83     @Override
onCreate(Bundle savedInstanceState)84     public void onCreate(Bundle savedInstanceState) {
85         super.onCreate(savedInstanceState);
86 
87         mBluetoothSwitch = new MenuItem.Builder(getContext())
88                 .setCheckable()
89                 .setOnClickListener(mBluetoothSwitchListener)
90                 .build();
91     }
92 
93     @Override
onAttach(Context context)94     public void onAttach(Context context) {
95         super.onAttach(context);
96         mUserManager = UserManager.get(context);
97         mLocalBluetoothManager = BluetoothUtils.getLocalBtManager(context);
98         if (mLocalBluetoothManager == null) {
99             goBack();
100         }
101     }
102 
103     @Override
onStart()104     public void onStart() {
105         super.onStart();
106         requireContext().registerReceiver(mReceiver, mIntentFilter);
107         mLocalBluetoothManager.setForegroundActivity(requireActivity());
108         handleStateChanged(mBluetoothAdapter.getState());
109     }
110 
111     @Override
onStop()112     public void onStop() {
113         super.onStop();
114         requireContext().unregisterReceiver(mReceiver);
115         mLocalBluetoothManager.setForegroundActivity(null);
116     }
117 
isUserRestricted()118     private boolean isUserRestricted() {
119         return mUserManager.hasUserRestriction(DISALLOW_BLUETOOTH);
120     }
121 
handleStateChanged(int state)122     private void handleStateChanged(int state) {
123         // Momentarily clear the listener so that we don't update the adapter while trying to
124         // reflect the adapter state.
125         mBluetoothSwitch.setOnClickListener(null);
126         switch (state) {
127             case BluetoothAdapter.STATE_TURNING_ON:
128                 mBluetoothSwitch.setEnabled(false);
129                 mBluetoothSwitch.setChecked(true);
130                 break;
131             case BluetoothAdapter.STATE_ON:
132                 mBluetoothSwitch.setEnabled(!isUserRestricted());
133                 mBluetoothSwitch.setChecked(true);
134                 break;
135             case BluetoothAdapter.STATE_TURNING_OFF:
136                 mBluetoothSwitch.setEnabled(false);
137                 mBluetoothSwitch.setChecked(false);
138                 break;
139             case BluetoothAdapter.STATE_OFF:
140             default:
141                 mBluetoothSwitch.setEnabled(!isUserRestricted());
142                 mBluetoothSwitch.setChecked(false);
143         }
144         mBluetoothSwitch.setOnClickListener(mBluetoothSwitchListener);
145     }
146 
147     public static final CarBaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
148             new CarBaseSearchIndexProvider(R.xml.bluetooth_settings_fragment,
149                     Settings.ACTION_BLUETOOTH_SETTINGS);
150 }
151