Removed setScanMode(int, long), setScanMode(int mode) is now a SystemApi. Made getDiscoverableTimeout a public API. setDiscoverableTimeout is now SystemApi. Discoverable timeout is now in seconds everywhere. Tag: #feature Bug: 195150096 Test: Manual Change-Id: Iee0a80b382f601a81f14afd7224637b88fbdf7ce
299 lines
11 KiB
Java
Executable File
299 lines
11 KiB
Java
Executable File
/*
|
|
* Copyright (C) 2008 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.android.settings.bluetooth;
|
|
|
|
import android.bluetooth.BluetoothAdapter;
|
|
import android.content.BroadcastReceiver;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.content.IntentFilter;
|
|
import android.content.SharedPreferences;
|
|
import android.os.Handler;
|
|
import android.os.SystemProperties;
|
|
import android.util.Log;
|
|
|
|
import androidx.preference.Preference;
|
|
|
|
import com.android.settings.R;
|
|
import com.android.settingslib.bluetooth.BluetoothDiscoverableTimeoutReceiver;
|
|
|
|
import java.time.Duration;
|
|
|
|
/**
|
|
* BluetoothDiscoverableEnabler is a helper to manage the "Discoverable"
|
|
* checkbox. It sets/unsets discoverability and keeps track of how much time
|
|
* until the the discoverability is automatically turned off.
|
|
*/
|
|
final class BluetoothDiscoverableEnabler implements Preference.OnPreferenceClickListener {
|
|
|
|
private static final String TAG = "BluetoothDiscoverableEnabler";
|
|
|
|
private static final String SYSTEM_PROPERTY_DISCOVERABLE_TIMEOUT =
|
|
"debug.bt.discoverable_time";
|
|
|
|
private static final int DISCOVERABLE_TIMEOUT_TWO_MINUTES = 120;
|
|
private static final int DISCOVERABLE_TIMEOUT_FIVE_MINUTES = 300;
|
|
private static final int DISCOVERABLE_TIMEOUT_ONE_HOUR = 3600;
|
|
static final int DISCOVERABLE_TIMEOUT_NEVER = 0;
|
|
|
|
// Bluetooth advanced settings screen was replaced with action bar items.
|
|
// Use the same preference key for discoverable timeout as the old ListPreference.
|
|
private static final String KEY_DISCOVERABLE_TIMEOUT = "bt_discoverable_timeout";
|
|
|
|
private static final String VALUE_DISCOVERABLE_TIMEOUT_TWO_MINUTES = "twomin";
|
|
private static final String VALUE_DISCOVERABLE_TIMEOUT_FIVE_MINUTES = "fivemin";
|
|
private static final String VALUE_DISCOVERABLE_TIMEOUT_ONE_HOUR = "onehour";
|
|
private static final String VALUE_DISCOVERABLE_TIMEOUT_NEVER = "never";
|
|
|
|
static final int DEFAULT_DISCOVERABLE_TIMEOUT = DISCOVERABLE_TIMEOUT_TWO_MINUTES;
|
|
|
|
private Context mContext;
|
|
private final Handler mUiHandler;
|
|
private final Preference mDiscoveryPreference;
|
|
|
|
private final BluetoothAdapter mBluetoothAdapter;
|
|
|
|
private final SharedPreferences mSharedPreferences;
|
|
|
|
private boolean mDiscoverable;
|
|
private int mNumberOfPairedDevices;
|
|
|
|
private int mTimeoutSecs = -1;
|
|
|
|
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
|
@Override
|
|
public void onReceive(Context context, Intent intent) {
|
|
if (BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(intent.getAction())) {
|
|
int mode = intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE,
|
|
BluetoothAdapter.ERROR);
|
|
if (mode != BluetoothAdapter.ERROR) {
|
|
handleModeChanged(mode);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
private final Runnable mUpdateCountdownSummaryRunnable = new Runnable() {
|
|
public void run() {
|
|
updateCountdownSummary();
|
|
}
|
|
};
|
|
|
|
BluetoothDiscoverableEnabler(Preference discoveryPreference) {
|
|
mUiHandler = new Handler();
|
|
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
|
mDiscoveryPreference = discoveryPreference;
|
|
mSharedPreferences = discoveryPreference.getSharedPreferences();
|
|
discoveryPreference.setPersistent(false);
|
|
}
|
|
|
|
public void resume(Context context) {
|
|
if (mBluetoothAdapter == null) {
|
|
return;
|
|
}
|
|
|
|
if (mContext != context) {
|
|
mContext = context;
|
|
}
|
|
|
|
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
|
|
mContext.registerReceiver(mReceiver, filter);
|
|
mDiscoveryPreference.setOnPreferenceClickListener(this);
|
|
handleModeChanged(mBluetoothAdapter.getScanMode());
|
|
}
|
|
|
|
public void pause() {
|
|
if (mBluetoothAdapter == null) {
|
|
return;
|
|
}
|
|
|
|
mUiHandler.removeCallbacks(mUpdateCountdownSummaryRunnable);
|
|
mContext.unregisterReceiver(mReceiver);
|
|
mDiscoveryPreference.setOnPreferenceClickListener(null);
|
|
}
|
|
|
|
public boolean onPreferenceClick(Preference preference) {
|
|
// toggle discoverability
|
|
mDiscoverable = !mDiscoverable;
|
|
setEnabled(mDiscoverable);
|
|
return true;
|
|
}
|
|
|
|
private void setEnabled(boolean enable) {
|
|
if (enable) {
|
|
int timeout = getDiscoverableTimeout();
|
|
long endTimestamp = System.currentTimeMillis() + timeout * 1000L;
|
|
LocalBluetoothPreferences.persistDiscoverableEndTimestamp(mContext, endTimestamp);
|
|
mBluetoothAdapter.setDiscoverableTimeout(Duration.ofSeconds(timeout));
|
|
mBluetoothAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);
|
|
updateCountdownSummary();
|
|
|
|
Log.d(TAG, "setEnabled(): enabled = " + enable + "timeout = " + timeout);
|
|
|
|
if (timeout > 0) {
|
|
BluetoothDiscoverableTimeoutReceiver.setDiscoverableAlarm(mContext, endTimestamp);
|
|
} else {
|
|
BluetoothDiscoverableTimeoutReceiver.cancelDiscoverableAlarm(mContext);
|
|
}
|
|
|
|
} else {
|
|
mBluetoothAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE);
|
|
BluetoothDiscoverableTimeoutReceiver.cancelDiscoverableAlarm(mContext);
|
|
}
|
|
}
|
|
|
|
private void updateTimerDisplay(int timeout) {
|
|
if (getDiscoverableTimeout() == DISCOVERABLE_TIMEOUT_NEVER) {
|
|
mDiscoveryPreference.setSummary(R.string.bluetooth_is_discoverable_always);
|
|
} else {
|
|
String textTimeout = formatTimeRemaining(timeout);
|
|
mDiscoveryPreference.setSummary(mContext.getString(R.string.bluetooth_is_discoverable,
|
|
textTimeout));
|
|
}
|
|
}
|
|
|
|
private static String formatTimeRemaining(int timeout) {
|
|
StringBuilder sb = new StringBuilder(6); // "mmm:ss"
|
|
int min = timeout / 60;
|
|
sb.append(min).append(':');
|
|
int sec = timeout - (min * 60);
|
|
if (sec < 10) {
|
|
sb.append('0');
|
|
}
|
|
sb.append(sec);
|
|
return sb.toString();
|
|
}
|
|
|
|
void setDiscoverableTimeout(int index) {
|
|
String timeoutValue;
|
|
switch (index) {
|
|
case 0:
|
|
default:
|
|
mTimeoutSecs = DISCOVERABLE_TIMEOUT_TWO_MINUTES;
|
|
timeoutValue = VALUE_DISCOVERABLE_TIMEOUT_TWO_MINUTES;
|
|
break;
|
|
|
|
case 1:
|
|
mTimeoutSecs = DISCOVERABLE_TIMEOUT_FIVE_MINUTES;
|
|
timeoutValue = VALUE_DISCOVERABLE_TIMEOUT_FIVE_MINUTES;
|
|
break;
|
|
|
|
case 2:
|
|
mTimeoutSecs = DISCOVERABLE_TIMEOUT_ONE_HOUR;
|
|
timeoutValue = VALUE_DISCOVERABLE_TIMEOUT_ONE_HOUR;
|
|
break;
|
|
|
|
case 3:
|
|
mTimeoutSecs = DISCOVERABLE_TIMEOUT_NEVER;
|
|
timeoutValue = VALUE_DISCOVERABLE_TIMEOUT_NEVER;
|
|
break;
|
|
}
|
|
mSharedPreferences.edit().putString(KEY_DISCOVERABLE_TIMEOUT, timeoutValue).apply();
|
|
setEnabled(true); // enable discovery and reset timer
|
|
}
|
|
|
|
private int getDiscoverableTimeout() {
|
|
if (mTimeoutSecs != -1) {
|
|
return mTimeoutSecs;
|
|
}
|
|
|
|
int timeout = SystemProperties.getInt(SYSTEM_PROPERTY_DISCOVERABLE_TIMEOUT, -1);
|
|
if (timeout < 0) {
|
|
String timeoutValue = mSharedPreferences.getString(KEY_DISCOVERABLE_TIMEOUT,
|
|
VALUE_DISCOVERABLE_TIMEOUT_TWO_MINUTES);
|
|
|
|
if (timeoutValue.equals(VALUE_DISCOVERABLE_TIMEOUT_NEVER)) {
|
|
timeout = DISCOVERABLE_TIMEOUT_NEVER;
|
|
} else if (timeoutValue.equals(VALUE_DISCOVERABLE_TIMEOUT_ONE_HOUR)) {
|
|
timeout = DISCOVERABLE_TIMEOUT_ONE_HOUR;
|
|
} else if (timeoutValue.equals(VALUE_DISCOVERABLE_TIMEOUT_FIVE_MINUTES)) {
|
|
timeout = DISCOVERABLE_TIMEOUT_FIVE_MINUTES;
|
|
} else {
|
|
timeout = DISCOVERABLE_TIMEOUT_TWO_MINUTES;
|
|
}
|
|
}
|
|
mTimeoutSecs = timeout;
|
|
return timeout;
|
|
}
|
|
|
|
int getDiscoverableTimeoutIndex() {
|
|
int timeout = getDiscoverableTimeout();
|
|
switch (timeout) {
|
|
case DISCOVERABLE_TIMEOUT_TWO_MINUTES:
|
|
default:
|
|
return 0;
|
|
|
|
case DISCOVERABLE_TIMEOUT_FIVE_MINUTES:
|
|
return 1;
|
|
|
|
case DISCOVERABLE_TIMEOUT_ONE_HOUR:
|
|
return 2;
|
|
|
|
case DISCOVERABLE_TIMEOUT_NEVER:
|
|
return 3;
|
|
}
|
|
}
|
|
|
|
void setNumberOfPairedDevices(int pairedDevices) {
|
|
mNumberOfPairedDevices = pairedDevices;
|
|
handleModeChanged(mBluetoothAdapter.getScanMode());
|
|
}
|
|
|
|
void handleModeChanged(int mode) {
|
|
Log.d(TAG, "handleModeChanged(): mode = " + mode);
|
|
if (mode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
|
|
mDiscoverable = true;
|
|
updateCountdownSummary();
|
|
} else {
|
|
mDiscoverable = false;
|
|
setSummaryNotDiscoverable();
|
|
}
|
|
}
|
|
|
|
private void setSummaryNotDiscoverable() {
|
|
if (mNumberOfPairedDevices != 0) {
|
|
mDiscoveryPreference.setSummary(R.string.bluetooth_only_visible_to_paired_devices);
|
|
} else {
|
|
mDiscoveryPreference.setSummary(R.string.bluetooth_not_visible_to_other_devices);
|
|
}
|
|
}
|
|
|
|
private void updateCountdownSummary() {
|
|
int mode = mBluetoothAdapter.getScanMode();
|
|
if (mode != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
|
|
return;
|
|
}
|
|
|
|
long currentTimestamp = System.currentTimeMillis();
|
|
long endTimestamp = LocalBluetoothPreferences.getDiscoverableEndTimestamp(mContext);
|
|
|
|
if (currentTimestamp > endTimestamp) {
|
|
// We're still in discoverable mode, but maybe there isn't a timeout.
|
|
updateTimerDisplay(0);
|
|
return;
|
|
}
|
|
|
|
int timeLeft = (int) ((endTimestamp - currentTimestamp) / 1000L);
|
|
updateTimerDisplay(timeLeft);
|
|
|
|
synchronized (this) {
|
|
mUiHandler.removeCallbacks(mUpdateCountdownSummaryRunnable);
|
|
mUiHandler.postDelayed(mUpdateCountdownSummaryRunnable, 1000);
|
|
}
|
|
}
|
|
}
|