1 /* 2 * Copyright (C) 2023 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.fastpair; 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.util.Log; 26 27 import androidx.annotation.NonNull; 28 import androidx.annotation.VisibleForTesting; 29 import androidx.lifecycle.DefaultLifecycleObserver; 30 import androidx.lifecycle.LifecycleOwner; 31 import androidx.preference.Preference; 32 import androidx.preference.PreferenceGroup; 33 import androidx.preference.PreferenceScreen; 34 35 import com.android.settings.connecteddevice.DevicePreferenceCallback; 36 import com.android.settings.core.BasePreferenceController; 37 import com.android.settings.core.PreferenceControllerMixin; 38 import com.android.settings.flags.Flags; 39 import com.android.settings.overlay.FeatureFactory; 40 41 /** 42 * Controller to maintain the {@link PreferenceGroup} for all Fast Pair devices. It uses {@link 43 * DevicePreferenceCallback} to add/remove {@link Preference} 44 */ 45 public class FastPairDeviceGroupController extends BasePreferenceController 46 implements PreferenceControllerMixin, DefaultLifecycleObserver, DevicePreferenceCallback { 47 48 private static final String TAG = "FastPairDeviceGroupCtr"; 49 50 private static final String KEY = "fast_pair_device_list"; 51 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 52 53 @VisibleForTesting PreferenceGroup mPreferenceGroup; 54 private final FastPairDeviceUpdater mFastPairDeviceUpdater; 55 private final BluetoothAdapter mBluetoothAdapter; 56 @VisibleForTesting IntentFilter mIntentFilter; 57 58 @VisibleForTesting 59 BroadcastReceiver mReceiver = 60 new BroadcastReceiver() { 61 @Override 62 public void onReceive(Context context, Intent intent) { 63 updatePreferenceVisibility(); 64 } 65 }; 66 FastPairDeviceGroupController(Context context)67 public FastPairDeviceGroupController(Context context) { 68 super(context, KEY); 69 if (Flags.enableSubsequentPairSettingsIntegration()) { 70 FastPairFeatureProvider fastPairFeatureProvider = 71 FeatureFactory.getFeatureFactory().getFastPairFeatureProvider(); 72 mFastPairDeviceUpdater = 73 fastPairFeatureProvider.getFastPairDeviceUpdater(context, this); 74 } else { 75 Log.d(TAG, "Flag disabled. Ignored."); 76 mFastPairDeviceUpdater = null; 77 } 78 mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 79 mIntentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED); 80 } 81 82 @Override onStart(@onNull LifecycleOwner owner)83 public void onStart(@NonNull LifecycleOwner owner) { 84 if (mFastPairDeviceUpdater != null) { 85 mFastPairDeviceUpdater.setPreferenceContext(mContext); 86 mFastPairDeviceUpdater.registerCallback(); 87 } else { 88 if (DEBUG) { 89 Log.d(TAG, "Callback register: Fast Pair device updater is null. Ignore."); 90 } 91 } 92 mContext.registerReceiver(mReceiver, mIntentFilter, Context.RECEIVER_EXPORTED_UNAUDITED); 93 } 94 95 @Override onStop(@onNull LifecycleOwner owner)96 public void onStop(@NonNull LifecycleOwner owner) { 97 if (mFastPairDeviceUpdater != null) { 98 mFastPairDeviceUpdater.setPreferenceContext(null); 99 mFastPairDeviceUpdater.unregisterCallback(); 100 } else { 101 if (DEBUG) { 102 Log.d(TAG, "Callback unregister: Fast Pair device updater is null. Ignore."); 103 } 104 } 105 mContext.unregisterReceiver(mReceiver); 106 } 107 108 @Override displayPreference(PreferenceScreen screen)109 public void displayPreference(PreferenceScreen screen) { 110 mPreferenceGroup = screen.findPreference(KEY); 111 mPreferenceGroup.setVisible(false); 112 113 if (isAvailable()) { 114 final Context context = screen.getContext(); 115 mFastPairDeviceUpdater.setPreferenceContext(context); 116 mFastPairDeviceUpdater.forceUpdate(); 117 } 118 } 119 120 @Override getAvailabilityStatus()121 public int getAvailabilityStatus() { 122 return (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH) 123 && mFastPairDeviceUpdater != null) 124 ? AVAILABLE 125 : UNSUPPORTED_ON_DEVICE; 126 } 127 128 @Override getPreferenceKey()129 public String getPreferenceKey() { 130 return KEY; 131 } 132 133 @Override onDeviceAdded(Preference preference)134 public void onDeviceAdded(Preference preference) { 135 if (preference == null) { 136 if (DEBUG) { 137 Log.d(TAG, "onDeviceAdded receives null preference. Ignore."); 138 } 139 return; 140 } 141 mPreferenceGroup.addPreference(preference); 142 updatePreferenceVisibility(); 143 } 144 145 @Override onDeviceRemoved(Preference preference)146 public void onDeviceRemoved(Preference preference) { 147 if (preference == null) { 148 if (DEBUG) { 149 Log.d(TAG, "onDeviceRemoved receives null preference. Ignore."); 150 } 151 return; 152 } 153 mPreferenceGroup.removePreference(preference); 154 updatePreferenceVisibility(); 155 } 156 updatePreferenceVisibility()157 private void updatePreferenceVisibility() { 158 mPreferenceGroup.setVisible( 159 mBluetoothAdapter != null 160 && mBluetoothAdapter.isEnabled() 161 && mPreferenceGroup.getPreferenceCount() > 0); 162 } 163 164 @VisibleForTesting setPreferenceGroup(PreferenceGroup preferenceGroup)165 public void setPreferenceGroup(PreferenceGroup preferenceGroup) { 166 mPreferenceGroup = preferenceGroup; 167 } 168 } 169