1 /* 2 * Copyright (C) 2024 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.bluetooth; 18 19 import android.bluetooth.BluetoothAdapter; 20 import android.content.Context; 21 import android.util.Log; 22 23 import androidx.annotation.NonNull; 24 import androidx.annotation.Nullable; 25 import androidx.annotation.VisibleForTesting; 26 import androidx.preference.PreferenceScreen; 27 import androidx.preference.TwoStatePreference; 28 29 import com.android.settings.core.TogglePreferenceController; 30 import com.android.settingslib.bluetooth.BluetoothCallback; 31 import com.android.settingslib.bluetooth.LocalBluetoothManager; 32 import com.android.settingslib.core.lifecycle.LifecycleObserver; 33 import com.android.settingslib.core.lifecycle.events.OnStart; 34 import com.android.settingslib.core.lifecycle.events.OnStop; 35 import com.android.settingslib.utils.ThreadUtils; 36 37 public class BluetoothAutoOnPreferenceController extends TogglePreferenceController 38 implements BluetoothCallback, LifecycleObserver, OnStart, OnStop { 39 private static final String TAG = "BluetoothAutoOnPrefCtlr"; 40 @VisibleForTesting static final String PREF_KEY = "bluetooth_auto_on_settings_toggle"; 41 @VisibleForTesting BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 42 private final LocalBluetoothManager mLocalBluetoothManager = Utils.getLocalBtManager(mContext); 43 private boolean mAutoOnValue = false; 44 @Nullable private TwoStatePreference mPreference; 45 BluetoothAutoOnPreferenceController( @onNull Context context, @NonNull String preferenceKey)46 public BluetoothAutoOnPreferenceController( 47 @NonNull Context context, @NonNull String preferenceKey) { 48 super(context, preferenceKey); 49 } 50 51 @Override onAutoOnStateChanged(int state)52 public void onAutoOnStateChanged(int state) { 53 var unused = 54 ThreadUtils.postOnBackgroundThread( 55 () -> { 56 Log.i(TAG, "onAutoOnStateChanged() state: " + state); 57 updateValue(); 58 mContext.getMainExecutor() 59 .execute( 60 () -> { 61 if (mPreference != null) { 62 updateState(mPreference); 63 } 64 }); 65 }); 66 } 67 68 @Override onStart()69 public void onStart() { 70 if (mLocalBluetoothManager == null) { 71 return; 72 } 73 mLocalBluetoothManager.getEventManager().registerCallback(this); 74 } 75 76 @Override onStop()77 public void onStop() { 78 if (mLocalBluetoothManager == null) { 79 return; 80 } 81 mLocalBluetoothManager.getEventManager().unregisterCallback(this); 82 } 83 84 @Override getAvailabilityStatus()85 public int getAvailabilityStatus() { 86 if (mBluetoothAdapter == null) { 87 return UNSUPPORTED_ON_DEVICE; 88 } 89 try { 90 boolean isSupported = mBluetoothAdapter.isAutoOnSupported(); 91 Log.i(TAG, "getAvailabilityStatus() isSupported: " + isSupported); 92 if (isSupported) { 93 var unused = ThreadUtils.postOnBackgroundThread(this::updateValue); 94 } 95 return isSupported ? AVAILABLE : UNSUPPORTED_ON_DEVICE; 96 } catch (Exception | NoSuchMethodError e) { 97 // Server could throw TimeoutException, InterruptedException or ExecutionException 98 return UNSUPPORTED_ON_DEVICE; 99 } 100 } 101 102 @Override displayPreference(@onNull PreferenceScreen screen)103 public void displayPreference(@NonNull PreferenceScreen screen) { 104 super.displayPreference(screen); 105 mPreference = screen.findPreference(getPreferenceKey()); 106 } 107 108 @Override getPreferenceKey()109 public String getPreferenceKey() { 110 return PREF_KEY; 111 } 112 113 @Override isChecked()114 public boolean isChecked() { 115 return mAutoOnValue; 116 } 117 118 @Override setChecked(boolean isChecked)119 public boolean setChecked(boolean isChecked) { 120 var unused = 121 ThreadUtils.postOnBackgroundThread( 122 () -> { 123 try { 124 mBluetoothAdapter.setAutoOnEnabled(isChecked); 125 } catch (Exception e) { 126 // Server could throw IllegalStateException, TimeoutException, 127 // InterruptedException or ExecutionException 128 Log.e(TAG, "Error calling setAutoOnEnabled()", e); 129 } 130 }); 131 return true; 132 } 133 134 @Override getSliceHighlightMenuRes()135 public int getSliceHighlightMenuRes() { 136 return 0; 137 } 138 updateValue()139 private void updateValue() { 140 if (mBluetoothAdapter == null) { 141 return; 142 } 143 try { 144 mAutoOnValue = mBluetoothAdapter.isAutoOnEnabled(); 145 } catch (Exception e) { 146 // Server could throw TimeoutException, InterruptedException or ExecutionException 147 Log.e(TAG, "Error calling isAutoOnEnabled()", e); 148 } 149 } 150 } 151