Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,10 @@
android:exported="false"
android:label="@string/information"
android:theme="@style/Theme.OpenTagViewer.GenericGreyishActivity" />
<activity
android:name=".ExtraSourcesSettingsActivity"
android:exported="false"
android:theme="@style/Theme.OpenTagViewer.GenericGreyishActivity" />
<activity
android:name=".SettingsActivity"
android:exported="false"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@
import dev.wander.android.opentagviewer.db.room.OpenTagViewerDatabase;
import dev.wander.android.opentagviewer.db.room.entity.Import;
import dev.wander.android.opentagviewer.db.room.entity.UserBeaconOptions;
import dev.wander.android.opentagviewer.source.ExternalAccessory;
import dev.wander.android.opentagviewer.ui.importing.ExternalDeviceImporter;
import dev.wander.android.opentagviewer.ui.compat.WindowPaddingUtil;
import dev.wander.android.opentagviewer.util.android.CachedPhoneLocation;
import dev.wander.android.opentagviewer.util.android.FusedPhoneLocation;
Expand Down Expand Up @@ -1097,6 +1099,9 @@ private void showPlaySoundStatus(final int messageRes, final int duration) {
* knows the most about.
*/
private String knownDeviceType() {
if (ExternalAccessory.isGoogle(this.accessoryJson())) {
return this.getString(R.string.google_find_hub_tracker);
}
if (this.beaconInformation.isCustomAccessory()) {
return this.getString(R.string.custom_tag);
}
Expand Down Expand Up @@ -1208,6 +1213,11 @@ private String getDeviceNameForTitle() {
return this.beaconInformation.getName();
}

private String accessoryJson() {
return this.beaconData == null || this.beaconData.getOwnedBeaconInfo() == null
? null : this.beaconData.getOwnedBeaconInfo().accessoryJson;
}

private void handleClickMenu() {
Log.d(TAG, "Device more button clicked");

Expand All @@ -1216,13 +1226,21 @@ private void handleClickMenu() {
var popupMenu = new PopupMenu(this, button);
popupMenu.getMenuInflater().inflate(R.menu.device_info_menu, popupMenu.getMenu());

// A Google tracker rings through FMDN (see RoutingSoundTrigger) and has nothing to link
popupMenu.getMenu().findItem(R.id.device_link_google)
.setVisible(!ExternalAccessory.isGoogle(this.accessoryJson()));

popupMenu.setOnMenuItemClickListener(menuItem -> {
Log.d(TAG, "Device menu option " + menuItem.getTitle() + " was selected");

if (menuItem.getItemId() == R.id.device_location_history) {
this.redirectToDeviceHistory();
} else if (menuItem.getItemId() == R.id.device_play_sound_nearby) {
this.onClickPlaySoundNearby();
} else if (menuItem.getItemId() == R.id.device_link_google) {
new ExternalDeviceImporter(this, () ->
Toast.makeText(this, R.string.google_link_saved, Toast.LENGTH_SHORT).show())
.linkGoogleTracker(this.beaconId);
} else if (menuItem.getItemId() == R.id.device_delete) {
this.onClickDeviceDelete();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package dev.wander.android.opentagviewer;

import android.os.Bundle;
import android.view.View;
import android.widget.EditText;

import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import dev.wander.android.opentagviewer.databinding.ActivityExtraSourcesBinding;
import dev.wander.android.opentagviewer.source.ExtraSourcesApi;
import dev.wander.android.opentagviewer.source.ExtraSourcesSettings;
import dev.wander.android.opentagviewer.ui.compat.WindowPaddingUtil;

/**
* Settings for the extra location source: googlefind (Google Find Hub trackers). Values are
* saved when the screen is left, like the rest of Settings.
*/
public class ExtraSourcesSettingsActivity extends AppCompatActivity {
private final ExecutorService io = Executors.newSingleThreadExecutor();
private ActivityExtraSourcesBinding binding;
private ExtraSourcesSettings settings;

private static final String[] KEYS = {
ExtraSourcesSettings.GOOGLE_URL, ExtraSourcesSettings.GOOGLE_TOKEN,
ExtraSourcesSettings.GOOGLE_USER, ExtraSourcesSettings.GOOGLE_PASSWORD,
};

private EditText[] fields() {
return new EditText[]{
binding.extraSourcesGoogleUrl, binding.extraSourcesGoogleToken,
binding.extraSourcesGoogleUser, binding.extraSourcesGooglePassword,
};
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.settings = new ExtraSourcesSettings(this);

this.binding = DataBindingUtil.setContentView(this, R.layout.activity_extra_sources);
WindowPaddingUtil.insetForSystemBarsAndKeyboard(this.binding.getRoot());
this.binding.setHandleClickBack(this::finish);
if (this.getSupportActionBar() != null) {
this.getSupportActionBar().hide();
}

final EditText[] fields = this.fields();
for (int i = 0; i < KEYS.length; i++) fields[i].setText(this.settings.get(KEYS[i]));

this.binding.extraSourcesTest.setOnClickListener(v -> this.test());
}

private void save() {
final EditText[] fields = this.fields();
for (int i = 0; i < KEYS.length; i++) this.settings.put(KEYS[i], fields[i].getText().toString());
}

@Override
protected void onPause() {
this.save();
super.onPause();
}

@Override
protected void onDestroy() {
this.io.shutdownNow();
super.onDestroy();
}

/** Asks the service something cheap and says whether it answered. */
private void test() {
this.save();
this.binding.extraSourcesTest.setEnabled(false);
this.binding.extraSourcesTestProgress.setVisibility(View.VISIBLE);
this.binding.extraSourcesTestResult.setText("");
this.io.execute(() -> {
final ExtraSourcesApi api = new ExtraSourcesApi(this.settings);
final StringBuilder result = new StringBuilder();
if (this.settings.isGoogleConfigured()) {
try {
final int count = api.googleDevices().size();
result.append(getString(R.string.test_google_ok, count));
} catch (final Exception e) {
result.append(getString(R.string.test_google_failed, e.getMessage()));
}
}
final String text = result.toString().trim();
runOnUiThread(() -> {
this.binding.extraSourcesTest.setEnabled(true);
this.binding.extraSourcesTestProgress.setVisibility(View.GONE);
this.binding.extraSourcesTestResult.setText(
text.isEmpty() ? getString(R.string.test_nothing_configured) : text);
});
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
import dev.wander.android.opentagviewer.db.room.OpenTagViewerDatabase;
import dev.wander.android.opentagviewer.db.room.entity.DailyHistoryFetchRecord;
import dev.wander.android.opentagviewer.db.util.BeaconCombinerUtil;
import dev.wander.android.opentagviewer.source.ReportSources;
import dev.wander.android.opentagviewer.python.AppDependencies;
import dev.wander.android.opentagviewer.python.PythonAppleService;
import dev.wander.android.opentagviewer.ui.compat.WindowPaddingUtil;
Expand Down Expand Up @@ -386,8 +387,14 @@ private Observable<List<BeaconLocationReport>> fetchReports(final long beginning
var reqData = BeaconRepository.plistFallback(
this.beaconId, this.beaconInformation.getOwnedBeaconPlistRaw());
// asyncReq emits Observable<FetchResult> (reports + updated accessory state per beacon)
// Each device through its own sources: the Apple account and Google Find Hub - see
// ReportSources.
var asyncReq = this.beaconRepo.toAccessoryRequests(reqData)
.flatMap(requests -> this.appleService.getReportsBetween(requests, beginningOfDay, endOfDay));
.flatMap(requests -> Observable.fromIterable(requests)
.concatMap(request -> ReportSources.create(this).fetch(
request, beginningOfDay, endOfDay, false,
this.appleService == null ? null
: this.appleService.getReportsBetween(List.of(request), beginningOfDay, endOfDay))));

// **What Apple returns is merged with what we already hold, for every day.**
//
Expand Down
Loading