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 }