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.homepage.contextualcards.slices; 18 19 import android.content.Context; 20 import android.net.Uri; 21 import android.os.Handler; 22 import android.os.HandlerThread; 23 import android.os.Looper; 24 import android.os.Process; 25 import android.util.Log; 26 27 import androidx.annotation.Nullable; 28 29 import com.android.settings.slices.SliceBackgroundWorker; 30 import com.android.settingslib.bluetooth.BluetoothCallback; 31 import com.android.settingslib.bluetooth.CachedBluetoothDevice; 32 import com.android.settingslib.bluetooth.LocalBluetoothManager; 33 34 public class BluetoothUpdateWorker extends SliceBackgroundWorker implements BluetoothCallback { 35 36 private static final String TAG = "BluetoothUpdateWorker"; 37 38 private static LocalBluetoothManager sLocalBluetoothManager; 39 40 private LoadBtManagerHandler mLoadBtManagerHandler; 41 BluetoothUpdateWorker(Context context, Uri uri)42 public BluetoothUpdateWorker(Context context, Uri uri) { 43 super(context, uri); 44 mLoadBtManagerHandler = LoadBtManagerHandler.getInstance(context); 45 if (sLocalBluetoothManager == null) { 46 mLoadBtManagerHandler.startLoadingBtManager(this); 47 } 48 } 49 50 /** Initialize {@link LocalBluetoothManager} in the background */ initLocalBtManager(Context context)51 public static void initLocalBtManager(Context context) { 52 if (sLocalBluetoothManager == null) { 53 LoadBtManagerHandler.getInstance(context).startLoadingBtManager(); 54 } 55 } 56 57 @Nullable getLocalBtManager()58 static LocalBluetoothManager getLocalBtManager() { 59 return sLocalBluetoothManager; 60 } 61 62 @Override onSlicePinned()63 protected void onSlicePinned() { 64 final LocalBluetoothManager localBtManager = mLoadBtManagerHandler.getLocalBtManager(); 65 if (localBtManager == null) { 66 return; 67 } 68 localBtManager.getEventManager().registerCallback(this); 69 } 70 71 @Override onSliceUnpinned()72 protected void onSliceUnpinned() { 73 final LocalBluetoothManager localBtManager = mLoadBtManagerHandler.getLocalBtManager(); 74 if (localBtManager == null) { 75 return; 76 } 77 localBtManager.getEventManager().unregisterCallback(this); 78 } 79 80 @Override close()81 public void close() { 82 } 83 84 @Override onAclConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state)85 public void onAclConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { 86 notifySliceChange(); 87 } 88 89 @Override onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile)90 public void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile) { 91 notifySliceChange(); 92 } 93 94 @Override onBluetoothStateChanged(int bluetoothState)95 public void onBluetoothStateChanged(int bluetoothState) { 96 notifySliceChange(); 97 } 98 99 @Override onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state)100 public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { 101 notifySliceChange(); 102 } 103 104 @Override onProfileConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state, int bluetoothProfile)105 public void onProfileConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state, 106 int bluetoothProfile) { 107 notifySliceChange(); 108 } 109 110 private static class LoadBtManagerHandler extends Handler { 111 112 private static LoadBtManagerHandler sHandler; 113 114 private final Runnable mLoadBtManagerTask; 115 private final Context mContext; 116 private BluetoothUpdateWorker mWorker; 117 getInstance(Context context)118 private static LoadBtManagerHandler getInstance(Context context) { 119 if (sHandler == null) { 120 final HandlerThread workerThread = new HandlerThread(TAG, 121 Process.THREAD_PRIORITY_BACKGROUND); 122 workerThread.start(); 123 sHandler = new LoadBtManagerHandler(context, workerThread.getLooper()); 124 } 125 return sHandler; 126 } 127 LoadBtManagerHandler(Context context, Looper looper)128 private LoadBtManagerHandler(Context context, Looper looper) { 129 super(looper); 130 mContext = context; 131 mLoadBtManagerTask = () -> { 132 Log.d(TAG, "LoadBtManagerHandler: start loading..."); 133 final long startTime = System.currentTimeMillis(); 134 sLocalBluetoothManager = getLocalBtManager(); 135 Log.d(TAG, "LoadBtManagerHandler took " + (System.currentTimeMillis() - startTime) 136 + " ms"); 137 }; 138 } 139 getLocalBtManager()140 private LocalBluetoothManager getLocalBtManager() { 141 if (sLocalBluetoothManager != null) { 142 return sLocalBluetoothManager; 143 } 144 return LocalBluetoothManager.getInstance(mContext, 145 (context, btManager) -> { 146 if (mWorker != null) { 147 // notify change if the worker is ready 148 mWorker.notifySliceChange(); 149 } 150 }); 151 } 152 startLoadingBtManager()153 private void startLoadingBtManager() { 154 if (!hasCallbacks(mLoadBtManagerTask)) { 155 post(mLoadBtManagerTask); 156 } 157 } 158 startLoadingBtManager(BluetoothUpdateWorker worker)159 private void startLoadingBtManager(BluetoothUpdateWorker worker) { 160 mWorker = worker; 161 startLoadingBtManager(); 162 } 163 } 164 }