1 /*
2  * Copyright (C) 2018 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.connecteddevice;
18 
19 import android.bluetooth.BluetoothAdapter;
20 import android.content.BroadcastReceiver;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.IntentFilter;
24 import android.content.pm.PackageManager;
25 import android.text.BidiFormatter;
26 import android.text.TextUtils;
27 
28 import androidx.annotation.VisibleForTesting;
29 import androidx.preference.PreferenceScreen;
30 
31 import com.android.settings.R;
32 import com.android.settings.bluetooth.AlwaysDiscoverable;
33 import com.android.settings.bluetooth.Utils;
34 import com.android.settings.core.BasePreferenceController;
35 import com.android.settingslib.bluetooth.LocalBluetoothManager;
36 import com.android.settingslib.core.lifecycle.LifecycleObserver;
37 import com.android.settingslib.core.lifecycle.events.OnStart;
38 import com.android.settingslib.core.lifecycle.events.OnStop;
39 import com.android.settingslib.widget.FooterPreference;
40 
41 /**
42  * Controller that shows and updates the bluetooth device name
43  */
44 public class DiscoverableFooterPreferenceController extends BasePreferenceController
45         implements LifecycleObserver, OnStart, OnStop {
46     private static final String KEY = "discoverable_footer_preference";
47 
48     @VisibleForTesting
49     BroadcastReceiver mBluetoothChangedReceiver;
50     @VisibleForTesting
51     LocalBluetoothManager mLocalManager;
52     private BluetoothAdapter mBluetoothAdapter;
53     private AlwaysDiscoverable mAlwaysDiscoverable;
54     private FooterPreference mPreference;
55     private boolean mIsAlwaysDiscoverable;
56 
DiscoverableFooterPreferenceController(Context context, String key)57     public DiscoverableFooterPreferenceController(Context context, String key) {
58         super(context, key);
59         mLocalManager = Utils.getLocalBtManager(context);
60         if (mLocalManager == null) {
61             return;
62         }
63         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
64         mAlwaysDiscoverable = new AlwaysDiscoverable(context);
65         initReceiver();
66     }
67 
68     @Override
displayPreference(PreferenceScreen screen)69     public void displayPreference(PreferenceScreen screen) {
70         super.displayPreference(screen);
71         mPreference = screen.findPreference(getPreferenceKey());
72     }
73 
74     @Override
getAvailabilityStatus()75     public int getAvailabilityStatus() {
76         return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)
77                 ? AVAILABLE_UNSEARCHABLE
78                 : UNSUPPORTED_ON_DEVICE;
79     }
80 
81     @Override
onStart()82     public void onStart() {
83         if (mLocalManager == null) {
84             return;
85         }
86         mContext.registerReceiver(mBluetoothChangedReceiver,
87                 new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
88         if (mIsAlwaysDiscoverable) {
89             mAlwaysDiscoverable.start();
90         }
91         updateFooterPreferenceTitle(mBluetoothAdapter.getState());
92     }
93 
94     @Override
onStop()95     public void onStop() {
96         if (mLocalManager == null) {
97             return;
98         }
99         mContext.unregisterReceiver(mBluetoothChangedReceiver);
100         if (mIsAlwaysDiscoverable) {
101             mAlwaysDiscoverable.stop();
102         }
103     }
104 
105     /**
106      * Set whether the device can be discovered. By default the value will be {@code false}.
107      *
108      * @param isAlwaysDiscoverable {@code true} if the device can be discovered,
109      *     otherwise {@code false}
110      */
setAlwaysDiscoverable(boolean isAlwaysDiscoverable)111     public void setAlwaysDiscoverable(boolean isAlwaysDiscoverable) {
112         mIsAlwaysDiscoverable = isAlwaysDiscoverable;
113     }
114 
updateFooterPreferenceTitle(int bluetoothState)115     private void updateFooterPreferenceTitle(int bluetoothState) {
116         if (bluetoothState == BluetoothAdapter.STATE_ON) {
117             mPreference.setTitle(getPreferenceTitle());
118         } else {
119             mPreference.setTitle(R.string.bluetooth_off_footer);
120         }
121     }
122 
getPreferenceTitle()123     private CharSequence getPreferenceTitle() {
124         final String deviceName = mBluetoothAdapter.getName();
125         if (TextUtils.isEmpty(deviceName)) {
126             return null;
127         }
128 
129         return TextUtils.expandTemplate(
130                 mContext.getText(R.string.bluetooth_device_name_summary),
131                 BidiFormatter.getInstance().unicodeWrap(deviceName));
132     }
133 
initReceiver()134     private void initReceiver() {
135         mBluetoothChangedReceiver = new BroadcastReceiver() {
136             @Override
137             public void onReceive(Context context, Intent intent) {
138                 if (intent.getAction().equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
139                     final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
140                             BluetoothAdapter.ERROR);
141                     updateFooterPreferenceTitle(state);
142                 }
143             }
144         };
145     }
146 }