* Copyright 2008-2009, Oliver Ruiz Dorantes, <oliver.ruiz.dorantes@gmail.com>
* Copyright 2021, Haiku, Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
* Fredrik Modéen <fredrik_at_modeen.se>
*/
#include <Alert.h>
#include <Button.h>
#include <Catalog.h>
#include <LayoutBuilder.h>
#include <ListView.h>
#include <ListItem.h>
#include <MessageRunner.h>
#include <ScrollView.h>
#include <StatusBar.h>
#include <SpaceLayoutItem.h>
#include <TextView.h>
#include <TabView.h>
#include <bluetooth/bdaddrUtils.h>
#include <bluetooth/DiscoveryAgent.h>
#include <bluetooth/DiscoveryListener.h>
#include <bluetooth/LocalDevice.h>
#include "defs.h"
#include "DeviceListItem.h"
#include "InquiryPanel.h"
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "Inquiry panel"
using Bluetooth::DeviceListItem;
extern uint8 GetInquiryTime();
static const uint32 kMsgStart = 'InSt';
static const uint32 kMsgFinish = 'InFn';
static const uint32 kMsgShowDebug = 'ShDG';
static const uint32 kMsgInquiry = 'iQbt';
static const uint32 kMsgAddListDevice = 'aDdv';
static const uint32 kMsgSelected = 'isLt';
static const uint32 kMsgSecond = 'sCMs';
static const uint32 kMsgRetrieve = 'IrEt';
class PanelDiscoveryListener : public DiscoveryListener {
public:
PanelDiscoveryListener(InquiryPanel* iPanel)
:
DiscoveryListener(),
fInquiryPanel(iPanel)
{
}
void
DeviceDiscovered(RemoteDevice* btDevice, DeviceClass cod)
{
BMessage* message = new BMessage(kMsgAddListDevice);
message->AddPointer("remoteItem", new DeviceListItem(btDevice));
fInquiryPanel->PostMessage(message);
}
void
InquiryCompleted(int discType)
{
BMessage* message = new BMessage(kMsgFinish);
fInquiryPanel->PostMessage(message);
}
void
InquiryStarted(status_t status)
{
BMessage* message = new BMessage(kMsgStart);
fInquiryPanel->PostMessage(message);
}
private:
InquiryPanel* fInquiryPanel;
};
InquiryPanel::InquiryPanel(BRect frame, LocalDevice* lDevice)
:
BWindow(frame, B_TRANSLATE_SYSTEM_NAME("Bluetooth"), B_FLOATING_WINDOW,
B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS, B_ALL_WORKSPACES ),
fMessenger(this),
fScanning(false),
fRetrieving(false),
fLocalDevice(lDevice)
{
fScanProgress = new BStatusBar("status",
B_TRANSLATE("Scanning progress"), "");
activeColor = fScanProgress->BarColor();
if (fLocalDevice == NULL)
fLocalDevice = LocalDevice::GetLocalDevice();
fMessage = new BTextView("description", B_WILL_DRAW);
fMessage->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
fMessage->SetLowColor(fMessage->ViewColor());
fMessage->MakeEditable(false);
fMessage->MakeSelectable(false);
fInquiryButton = new BButton("Inquiry", B_TRANSLATE("Inquiry"),
new BMessage(kMsgInquiry), B_WILL_DRAW);
fAddButton = new BButton("add", B_TRANSLATE("Add device to list"),
new BMessage(kMsgAddToRemoteList), B_WILL_DRAW);
fAddButton->SetEnabled(false);
fRemoteList = new BListView("AttributeList", B_SINGLE_SELECTION_LIST);
fRemoteList->SetSelectionMessage(new BMessage(kMsgSelected));
fScrollView = new BScrollView("ScrollView", fRemoteList, 0, false, true);
fScrollView->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
if (fLocalDevice != NULL) {
fMessage->SetText(B_TRANSLATE(
"Check that the Bluetooth capabilities of your"
" remote device are activated. Press 'Inquiry' to start scanning."
" The needed time for the retrieval of the names is unknown, "
"although should not take more than 3 seconds per device. "
"Afterwards you will be able to add them to your main list,"
" where you will be able to pair with them."));
fInquiryButton->SetEnabled(true);
fDiscoveryAgent = fLocalDevice->GetDiscoveryAgent();
fDiscoveryListener = new PanelDiscoveryListener(this);
SetTitle((const char*)(fLocalDevice->GetFriendlyName().String()));
} else {
fMessage->SetText(B_TRANSLATE("There isn't any Bluetooth LocalDevice "
"registered on the system."));
fInquiryButton->SetEnabled(false);
}
fRetrieveMessage = new BMessage(kMsgRetrieve);
fSecondsMessage = new BMessage(kMsgSecond);
BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
.SetInsets(B_USE_SMALL_SPACING)
.Add(fMessage, 0)
.Add(fScanProgress, 10)
.Add(fScrollView, 20)
.AddGroup(B_HORIZONTAL, 10)
.Add(fAddButton)
.AddGlue()
.Add(fInquiryButton)
.End()
.End();
}
void
InquiryPanel::MessageReceived(BMessage* message)
{
static float timer = 0;
static float scanningTime = 0;
static int32 retrievalIndex = 0;
static bool labelPlaced = false;
switch (message->what) {
case kMsgInquiry:
fDiscoveryAgent->StartInquiry(BT_GIAC, fDiscoveryListener, GetInquiryTime());
timer = BT_BASE_INQUIRY_TIME * GetInquiryTime() + 1;
fScanProgress->SetMaxValue(timer);
break;
case kMsgAddListDevice:
{
DeviceListItem* listItem;
message->FindPointer("remoteItem", (void **)&listItem);
fRemoteList->AddItem(listItem);
}
break;
case kMsgAddToRemoteList:
{
message->PrintToStream();
int32 index = fRemoteList->CurrentSelection(0);
DeviceListItem* item = (DeviceListItem*) fRemoteList->RemoveItem(index);;
BMessage message(kMsgAddToRemoteList);
message.AddPointer("device", item);
be_app->PostMessage(&message);
}
break;
case kMsgSelected:
UpdateListStatus();
break;
case kMsgStart:
fRemoteList->MakeEmpty();
fScanProgress->Reset();
fScanProgress->SetTo(1);
fScanProgress->SetTrailingText(B_TRANSLATE("Starting scan"
B_UTF8_ELLIPSIS));
fScanProgress->SetBarColor(activeColor);
fAddButton->SetEnabled(false);
fInquiryButton->SetEnabled(false);
BMessageRunner::StartSending(fMessenger, fSecondsMessage, 1000000, timer);
scanningTime = 1;
fScanning = true;
break;
case kMsgFinish:
retrievalIndex = 0;
fScanning = false;
fRetrieving = true;
labelPlaced = false;
fScanProgress->SetTo(100);
fScanProgress->SetTrailingText(B_TRANSLATE("Retrieving names"
B_UTF8_ELLIPSIS));
BMessageRunner::StartSending(fMessenger, fRetrieveMessage, 1000000, 1);
break;
case kMsgSecond:
if (fScanning && scanningTime < timer) {
fScanProgress->SetTo(scanningTime * 100 / timer);
BString elapsedTime = B_TRANSLATE("Remaining %1 seconds");
BString seconds("");
seconds << (int)(timer - scanningTime);
elapsedTime.ReplaceFirst("%1", seconds.String());
fScanProgress->SetTrailingText(elapsedTime.String());
scanningTime = scanningTime + 1;
}
break;
case kMsgRetrieve:
if (fRetrieving) {
if (retrievalIndex < fDiscoveryAgent->RetrieveDevices(0).CountItems()) {
if (!labelPlaced) {
labelPlaced = true;
BString progressText(B_TRANSLATE("Retrieving name of %1"));
BString namestr;
namestr << bdaddrUtils::ToString(fDiscoveryAgent
->RetrieveDevices(0).ItemAt(retrievalIndex)
->GetBluetoothAddress());
progressText.ReplaceFirst("%1", namestr.String());
fScanProgress->SetTrailingText(progressText.String());
} else {
((DeviceListItem*)fRemoteList->ItemAt(retrievalIndex))
->SetDevice((BluetoothDevice*) fDiscoveryAgent
->RetrieveDevices(0).ItemAt(retrievalIndex));
fRemoteList->InvalidateItem(retrievalIndex);
retrievalIndex++;
labelPlaced = false;
}
BMessageRunner::StartSending(fMessenger, fRetrieveMessage, 500000, 1);
} else {
fRetrieving = false;
retrievalIndex = 0;
fScanProgress->SetBarColor(
ui_color(B_PANEL_BACKGROUND_COLOR));
fScanProgress->SetTrailingText(
B_TRANSLATE("Scanning completed."));
fInquiryButton->SetEnabled(true);
UpdateListStatus();
}
}
break;
default:
BWindow::MessageReceived(message);
break;
}
}
void
InquiryPanel::UpdateListStatus(void)
{
if (fRemoteList->CurrentSelection() < 0 || fScanning || fRetrieving)
fAddButton->SetEnabled(false);
else
fAddButton->SetEnabled(true);
}
bool
InquiryPanel::QuitRequested(void)
{
return true;
}