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.settings.dashboard.DashboardFragment;
36 import com.android.settingslib.bluetooth.LocalBluetoothManager;
37 import com.android.settingslib.core.lifecycle.LifecycleObserver;
38 import com.android.settingslib.core.lifecycle.events.OnPause;
39 import com.android.settingslib.core.lifecycle.events.OnResume;
40 import com.android.settingslib.widget.FooterPreference;
41 import com.android.settingslib.widget.FooterPreferenceMixinCompat;
42 
43 /**
44  * Controller that shows and updates the bluetooth device name
45  */
46 public class DiscoverableFooterPreferenceController extends BasePreferenceController
47         implements LifecycleObserver, OnResume, OnPause {
48     private static final String KEY = "discoverable_footer_preference";
49 
50     @VisibleForTesting
51     BroadcastReceiver mBluetoothChangedReceiver;
52     @VisibleForTesting
53     LocalBluetoothManager mLocalManager;
54     private FooterPreferenceMixinCompat mFooterPreferenceMixin;
55     private FooterPreference mPreference;
56     private BluetoothAdapter mBluetoothAdapter;
57     private AlwaysDiscoverable mAlwaysDiscoverable;
58 
DiscoverableFooterPreferenceController(Context context)59     public DiscoverableFooterPreferenceController(Context context) {
60         super(context, KEY);
61         mLocalManager = Utils.getLocalBtManager(context);
62         if (mLocalManager == null) {
63             return;
64         }
65         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
66         mAlwaysDiscoverable = new AlwaysDiscoverable(context);
67         initReceiver();
68     }
69 
initReceiver()70     private void initReceiver() {
71         mBluetoothChangedReceiver = new BroadcastReceiver() {
72             @Override
73             public void onReceive(Context context, Intent intent) {
74                 if (intent.getAction().equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
75                     final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
76                             BluetoothAdapter.ERROR);
77                     updateFooterPreferenceTitle(state);
78                 }
79             }
80         };
81     }
82 
init(DashboardFragment fragment)83     public void init(DashboardFragment fragment) {
84         mFooterPreferenceMixin = new FooterPreferenceMixinCompat(fragment,
85                 fragment.getSettingsLifecycle());
86     }
87 
88     @VisibleForTesting
init(FooterPreferenceMixinCompat footerPreferenceMixin, FooterPreference preference, AlwaysDiscoverable alwaysDiscoverable)89     void init(FooterPreferenceMixinCompat footerPreferenceMixin, FooterPreference preference,
90             AlwaysDiscoverable alwaysDiscoverable) {
91         mFooterPreferenceMixin = footerPreferenceMixin;
92         mPreference = preference;
93         mAlwaysDiscoverable = alwaysDiscoverable;
94     }
95 
96     @Override
displayPreference(PreferenceScreen screen)97     public void displayPreference(PreferenceScreen screen) {
98         super.displayPreference(screen);
99         addFooterPreference(screen);
100     }
101 
102     @Override
getAvailabilityStatus()103     public int getAvailabilityStatus() {
104         return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)
105                 ? AVAILABLE
106                 : UNSUPPORTED_ON_DEVICE;
107     }
108 
addFooterPreference(PreferenceScreen screen)109     private void addFooterPreference(PreferenceScreen screen) {
110         mPreference = mFooterPreferenceMixin.createFooterPreference();
111         mPreference.setKey(KEY);
112         screen.addPreference(mPreference);
113     }
114 
115     @Override
onResume()116     public void onResume() {
117         if (mLocalManager == null) {
118             return;
119         }
120         mContext.registerReceiver(mBluetoothChangedReceiver,
121                 new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
122         mAlwaysDiscoverable.start();
123         updateFooterPreferenceTitle(mBluetoothAdapter.getState());
124     }
125 
126     @Override
onPause()127     public void onPause() {
128         if (mLocalManager == null) {
129             return;
130         }
131         mContext.unregisterReceiver(mBluetoothChangedReceiver);
132         mAlwaysDiscoverable.stop();
133     }
134 
updateFooterPreferenceTitle(int bluetoothState)135     private void updateFooterPreferenceTitle (int bluetoothState) {
136         if (bluetoothState == BluetoothAdapter.STATE_ON) {
137             mPreference.setTitle(getPreferenceTitle());
138         } else {
139             mPreference.setTitle(R.string.bluetooth_off_footer);
140         }
141     }
142 
getPreferenceTitle()143     private CharSequence getPreferenceTitle() {
144         final String deviceName = mBluetoothAdapter.getName();
145         if (TextUtils.isEmpty(deviceName)) {
146             return null;
147         }
148 
149         return TextUtils.expandTemplate(
150                 mContext.getText(R.string.bluetooth_device_name_summary),
151                 BidiFormatter.getInstance().unicodeWrap(deviceName));
152     }
153 }