1 /* 2 * Copyright (C) 2008 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.app.ActivityManager; 20 import android.bluetooth.BluetoothAdapter; 21 import android.bluetooth.BluetoothDevice; 22 import android.content.Context; 23 import android.content.SharedPreferences; 24 import android.content.res.Configuration; 25 import android.text.TextUtils; 26 import android.util.Log; 27 28 import androidx.annotation.Nullable; 29 30 import com.android.settingslib.bluetooth.LocalBluetoothManager; 31 32 /** 33 * LocalBluetoothPreferences provides an interface to the preferences 34 * related to Bluetooth. 35 */ 36 final class LocalBluetoothPreferences { 37 private static final String TAG = "LocalBluetoothPreferences"; 38 private static final boolean DEBUG = Utils.D; 39 private static final String SHARED_PREFERENCES_NAME = "bluetooth_settings"; 40 41 // If a device was picked from the device picker or was in discoverable mode 42 // in the last 60 seconds, show the pairing dialogs in foreground instead 43 // of raising notifications 44 private static final int GRACE_PERIOD_TO_SHOW_DIALOGS_IN_FOREGROUND = 60 * 1000; 45 46 private static final String KEY_LAST_SELECTED_DEVICE = "last_selected_device"; 47 48 private static final String KEY_LAST_SELECTED_DEVICE_TIME = "last_selected_device_time"; 49 50 private static final String KEY_DISCOVERABLE_END_TIMESTAMP = "discoverable_end_timestamp"; 51 LocalBluetoothPreferences()52 private LocalBluetoothPreferences() { 53 } 54 getSharedPreferences(Context context)55 private static SharedPreferences getSharedPreferences(Context context) { 56 return context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE); 57 } 58 getDiscoverableEndTimestamp(Context context)59 static long getDiscoverableEndTimestamp(Context context) { 60 return getSharedPreferences(context).getLong( 61 KEY_DISCOVERABLE_END_TIMESTAMP, 0); 62 } 63 shouldShowDialogInForeground(Context context, @Nullable BluetoothDevice device)64 static boolean shouldShowDialogInForeground(Context context, @Nullable BluetoothDevice device) { 65 String deviceAddress = device != null ? device.getAddress() : null; 66 String deviceName = device != null ? device.getName() : null; 67 LocalBluetoothManager manager = Utils.getLocalBtManager(context); 68 if (manager == null) { 69 if (DEBUG) Log.v(TAG, "manager == null - do not show dialog."); 70 return false; 71 } 72 73 // If Bluetooth Settings is visible 74 if (manager.isForegroundActivity()) { 75 return true; 76 } 77 78 // If in appliance mode, do not show dialog in foreground. 79 if ((context.getResources().getConfiguration().uiMode & 80 Configuration.UI_MODE_TYPE_APPLIANCE) == Configuration.UI_MODE_TYPE_APPLIANCE) { 81 if (DEBUG) Log.v(TAG, "in appliance mode - do not show dialog."); 82 return false; 83 } 84 85 long currentTimeMillis = System.currentTimeMillis(); 86 SharedPreferences sharedPreferences = getSharedPreferences(context); 87 88 // If the device was in discoverABLE mode recently 89 long lastDiscoverableEndTime = sharedPreferences.getLong( 90 KEY_DISCOVERABLE_END_TIMESTAMP, 0); 91 if ((lastDiscoverableEndTime + GRACE_PERIOD_TO_SHOW_DIALOGS_IN_FOREGROUND) 92 > currentTimeMillis) { 93 return true; 94 } 95 96 // If the device was discoverING recently 97 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 98 if (adapter != null) { 99 if (adapter.isDiscovering()) { 100 return true; 101 } 102 if ((adapter.getDiscoveryEndMillis() + 103 GRACE_PERIOD_TO_SHOW_DIALOGS_IN_FOREGROUND) > currentTimeMillis) { 104 return true; 105 } 106 } 107 108 // If the device was picked in the device picker recently 109 if (deviceAddress != null) { 110 String lastSelectedDevice = sharedPreferences.getString( 111 KEY_LAST_SELECTED_DEVICE, null); 112 113 if (deviceAddress.equals(lastSelectedDevice)) { 114 long lastDeviceSelectedTime = sharedPreferences.getLong( 115 KEY_LAST_SELECTED_DEVICE_TIME, 0); 116 if ((lastDeviceSelectedTime + GRACE_PERIOD_TO_SHOW_DIALOGS_IN_FOREGROUND) 117 > currentTimeMillis) { 118 return true; 119 } 120 } 121 } 122 123 124 if (!TextUtils.isEmpty(deviceName)) { 125 // If the device is a custom BT keyboard specifically for this device 126 String packagedKeyboardName = context.getString( 127 com.android.internal.R.string.config_packagedKeyboardName); 128 if (deviceName.equals(packagedKeyboardName)) { 129 if (DEBUG) Log.v(TAG, "showing dialog for packaged keyboard"); 130 return true; 131 } 132 } 133 134 if (device != null) { 135 ActivityManager activityManager = context.getSystemService(ActivityManager.class); 136 String packageName = device.getPackageNameOfBondingApplication(); 137 138 if (packageName != null && activityManager.getPackageImportance(packageName) 139 == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { 140 if (DEBUG) { 141 Log.v(TAG, "showing dialog because the initiating application " 142 + "is in foreground"); 143 } 144 return true; 145 } 146 } 147 148 if (DEBUG) Log.v(TAG, "Found no reason to show the dialog - do not show dialog."); 149 return false; 150 } 151 persistSelectedDeviceInPicker(Context context, String deviceAddress)152 static void persistSelectedDeviceInPicker(Context context, String deviceAddress) { 153 SharedPreferences.Editor editor = getSharedPreferences(context).edit(); 154 editor.putString(KEY_LAST_SELECTED_DEVICE, 155 deviceAddress); 156 editor.putLong(KEY_LAST_SELECTED_DEVICE_TIME, 157 System.currentTimeMillis()); 158 editor.apply(); 159 } 160 persistDiscoverableEndTimestamp(Context context, long endTimestamp)161 static void persistDiscoverableEndTimestamp(Context context, long endTimestamp) { 162 SharedPreferences.Editor editor = getSharedPreferences(context).edit(); 163 editor.putLong(KEY_DISCOVERABLE_END_TIMESTAMP, endTimestamp); 164 editor.apply(); 165 } 166 } 167