diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index eba949e..0532d23 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -5,8 +5,21 @@
android:versionCode="160"
android:versionName="2.20.1">
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/assets/found.mp3 b/app/src/main/assets/found.mp3
new file mode 100644
index 0000000..67088c1
Binary files /dev/null and b/app/src/main/assets/found.mp3 differ
diff --git a/app/src/main/assets/lost.mp3 b/app/src/main/assets/lost.mp3
index f631fac..16dc40d 100644
Binary files a/app/src/main/assets/lost.mp3 and b/app/src/main/assets/lost.mp3 differ
diff --git a/app/src/main/java/s4y/itag/BootReceiver.java b/app/src/main/java/s4y/itag/BootReceiver.java
index 5d5a7d6..aeecd9f 100644
--- a/app/src/main/java/s4y/itag/BootReceiver.java
+++ b/app/src/main/java/s4y/itag/BootReceiver.java
@@ -22,7 +22,7 @@ public void onReceive(@NonNull Context context, @NonNull Intent intent) {
"android.intent.action.QUICKBOOT_POWERON".equals(intent.getAction())
) {
ITagsStoreInterface store = new ITagsStoreDefault(ITagApplication.context);
- if (store.isDisconnectAlert()) {
+ if (store.isDisconnectAlertOn()) {
ITagsService.start(context);
// expected to create application and thus init waytooday
// and enter foreground
diff --git a/app/src/main/java/s4y/itag/ITagApplication.java b/app/src/main/java/s4y/itag/ITagApplication.java
index 42571a6..91903b8 100644
--- a/app/src/main/java/s4y/itag/ITagApplication.java
+++ b/app/src/main/java/s4y/itag/ITagApplication.java
@@ -248,7 +248,7 @@ static public void faWtNoTrackID() {
@Override
public void onTerminate() {
try {
- ITag.close();
+ ITag.closeApplication();
} catch (Exception e) {
e.printStackTrace();
}
diff --git a/app/src/main/java/s4y/itag/ITagImageView.java b/app/src/main/java/s4y/itag/ITagImageView.java
index 27ed802..c4a29d2 100644
--- a/app/src/main/java/s4y/itag/ITagImageView.java
+++ b/app/src/main/java/s4y/itag/ITagImageView.java
@@ -1,13 +1,22 @@
package s4y.itag;
+import android.animation.ObjectAnimator;
import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatImageView;
public class ITagImageView extends AppCompatImageView {
+ private static final String LT = ITagImageView.class.getName();
+
public ITagImageView(Context context) {
super(context);
}
@@ -20,4 +29,69 @@ public ITagImageView(Context context, @Nullable AttributeSet attrs, int defStyle
super(context, attrs, defStyleAttr);
}
+ private static final int CLICK_INTERVAL = ViewConfiguration.getLongPressTimeout();
+
+ private final android.os.Handler clickHandler = new Handler(Looper.getMainLooper());
+ private final Runnable waitNext = () -> {
+ isLongPress = true;
+ Log.d(LT, "waitNext called");
+ };
+
+ boolean isLongPress = false;
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ super.onTouchEvent(event);
+
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ clickHandler.postDelayed(waitNext, CLICK_INTERVAL);
+ Log.d(LT, "action down");
+ startScaleAnimation(this);
+ return true;
+ case MotionEvent.ACTION_UP:
+ clickHandler.removeCallbacks(waitNext);
+ cancelScaleAnimation(this);
+ Log.d(LT, "callbacks removed");
+ if(isLongPress){
+ //performLongClick();
+ Log.d(LT, "is longpress");
+ isLongPress = false;
+ } else {
+ Log.d(LT, "call performClick");
+ }
+ return true;
+ }
+ return false;
+ }
+
+ // Because we call this from onTouchEvent, this code will be executed for both
+ // normal touch events and for when the system calls this using Accessibility
+ @Override
+ public boolean performClick() {
+ super.performClick();
+ Log.d(LT, "super.performClick()");
+ return true;
+ }
+
+ private void startScaleAnimation(View view) {
+ ObjectAnimator scaleDownX = ObjectAnimator.ofFloat(view, "scaleX", 0.8f);
+ ObjectAnimator scaleDownY = ObjectAnimator.ofFloat(view, "scaleY", 0.8f);
+ scaleDownX.setDuration(150);
+ scaleDownY.setDuration(150);
+
+ scaleDownX.start();
+ scaleDownY.start();
+ }
+
+ private void cancelScaleAnimation(View view) {
+ ObjectAnimator scaleDownX = ObjectAnimator.ofFloat(view, "scaleX", 1.0f);
+ ObjectAnimator scaleDownY = ObjectAnimator.ofFloat(view, "scaleY", 1.0f);
+ scaleDownX.setDuration(150);
+ scaleDownY.setDuration(150);
+
+ scaleDownX.start();
+ scaleDownY.start();
+ }
+
}
diff --git a/app/src/main/java/s4y/itag/ITagsFragment.java b/app/src/main/java/s4y/itag/ITagsFragment.java
index 6016543..d3f475d 100644
--- a/app/src/main/java/s4y/itag/ITagsFragment.java
+++ b/app/src/main/java/s4y/itag/ITagsFragment.java
@@ -1,6 +1,9 @@
package s4y.itag;
import android.app.Activity;
+import android.content.SharedPreferences;
+import android.graphics.Color;
+import android.os.Build;
import android.os.Bundle;
import android.os.Looper;
import android.util.Log;
@@ -10,6 +13,7 @@
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
+import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
@@ -35,7 +39,9 @@
public class ITagsFragment extends Fragment implements HistoryRecord.HistoryRecordListener {
private static final String LT = ITagsFragment.class.getName();
private Animation mLocationAnimation;
- private Animation mITagAnimation;
+ private Animation mITagAnimationShakeIndefinitely;
+ private Animation mITagAnimationShakeOnce;
+ private String trackID = "";
private final DisposableBag disposableBag = new DisposableBag();
public ITagsFragment() {
@@ -44,6 +50,28 @@ public ITagsFragment() {
private final Map tagViews = new HashMap<>();
+ public void updateTags(boolean firstTime){
+ Log.d("ingo", "firstTime " + firstTime);
+ for (Map.Entry entry : tagViews.entrySet()) {
+ String id = entry.getKey();
+ ViewGroup rootView = entry.getValue();
+ ITagInterface itag = ITag.store.byId(id);
+ BLEConnectionInterface connection = ble.connectionById(id);
+ if (itag != null) {
+ setupButtons(rootView, itag);
+ updateITagImage(rootView, itag);
+ updateITagImageAnimation(rootView, itag, connection);
+ updateName(rootView, itag);
+ updateAlertButton(rootView, itag.isConnectModeEnabled(), connection.isConnected());
+ }
+ updateRSSI(rootView, connection.rssi());
+ updateState(rootView, id, connection.state());
+ updateLocationImage(rootView, id);
+ }
+
+ updateWayToday();
+ }
+
private void setupTags(@NonNull ViewGroup root) {
Activity activity = getActivity();
if (activity == null) return; //
@@ -55,58 +83,21 @@ private void setupTags(@NonNull ViewGroup root) {
index = root.indexOfChild(tagsLayout);
}
final int s = ITag.store.count();
+ Log.d("ingo", "s je " + s);
final int rid = s == 0 ? R.layout.itag_0 : s == 1 ? R.layout.itag_1 : s == 2 ? R.layout.itag_2 : s == 3 ? R.layout.itag_3 : R.layout.itag_4;
tagsLayout = activity.getLayoutInflater().inflate(rid, root, false);
root.addView(tagsLayout, index);
tagViews.clear();
- if (s > 0) {
- ITagInterface itag = ITag.store.byPos(0);
- if (itag != null) {
- tagViews.put(itag.id(), root.findViewById(R.id.tag_1).findViewById(R.id.layout_itag));
- }
- }
-
- if (s > 1) {
- ITagInterface itag = ITag.store.byPos(1);
- if (itag != null) {
- tagViews.put(itag.id(), root.findViewById(R.id.tag_2).findViewById(R.id.layout_itag));
- }
- }
-
- if (s > 2) {
- ITagInterface itag = ITag.store.byPos(2);
- if (itag != null) {
- tagViews.put(itag.id(), root.findViewById(R.id.tag_3).findViewById(R.id.layout_itag));
- }
- }
-
- if (s > 3) {
- ITagInterface itag = ITag.store.byPos(3);
- if (itag != null) {
- tagViews.put(itag.id(), root.findViewById(R.id.tag_4).findViewById(R.id.layout_itag));
- }
- }
-
- for (Map.Entry entry : tagViews.entrySet()) {
- String id = entry.getKey();
- ViewGroup rootView = entry.getValue();
- ITagInterface itag = ITag.store.byId(id);
- BLEConnectionInterface connection = ble.connectionById(id);
+ int[] tag_ids = new int[]{R.id.tag_1, R.id.tag_2, R.id.tag_3, R.id.tag_4};
+ for(int i = 0; i <= s; i++){
+ ITagInterface itag = ITag.store.byPos(i);
if (itag != null) {
- setupButtons(rootView, itag);
- updateITagImage(rootView, itag);
- updateITagImageAnimation(rootView, itag, connection);
- updateName(rootView, itag.name());
- updateAlertButton(rootView, itag.isAlertDisconnected(), connection.isConnected());
+ tagViews.put(itag.id(), root.findViewById(tag_ids[i]).findViewById(R.id.layout_itag));
}
- int rssi = connection.state() == BLEConnectionState.connected ? connection.rssi() : -999;
- updateRSSI(rootView, rssi);
- updateState(rootView, id, connection.state());
- updateLocationImage(rootView, id);
}
- updateWayToday();
+ updateTags(true);
}
private void setupButtons(@NonNull ViewGroup rootView, @NonNull final ITagInterface itag) {
@@ -174,7 +165,7 @@ private void updateLocationImage(@NonNull ViewGroup rootView, @NonNull String id
imageLocation.setVisibility(View.GONE);
} else {
Log.d(LT, "updateLocationImage on:" + id);
- imageLocation.startAnimation(mLocationAnimation);
+ //imageLocation.startAnimation(mLocationAnimation);
imageLocation.setVisibility(View.VISIBLE);
}
}
@@ -198,10 +189,15 @@ private void updateRSSI(@NonNull ViewGroup rootView, int rssi) {
Activity activity = getActivity();
if (activity == null) return; //
RssiView rssiView = rootView.findViewById(R.id.rssi);
- if (rssiView == null) {
- return;
+ TextView rssiTextView = rootView.findViewById(R.id.text_rssi);
+ if (rssiView != null) {
+ rssiView.setRssi(rssi);
+ }
+ if (rssiTextView != null) {
+ getActivity().runOnUiThread(() -> {
+ rssiTextView.setText(String.format(getString(R.string.rssi), rssi));
+ });
}
- rssiView.setRssi(rssi);
}
private void updateRSSI(@NonNull String id, int rssi) {
@@ -216,24 +212,38 @@ private void updateState(@NonNull ViewGroup rootView, @NonNull String id, @NonNu
Activity activity = getActivity();
if (activity == null) return; //
int statusDrawableId;
+ int statusDrawableTint = Color.BLACK;
int statusTextId;
+ boolean progressBar = false;
if (ble.state() == BLEState.OK) {
+ ITagInterface itag = ITag.store.byId(id);
switch (state) {
case connected:
statusDrawableId = R.drawable.bt;
+ statusDrawableTint = Color.GREEN;
statusTextId = R.string.bt;
break;
- case connecting:
- case disconnecting:
- ITagInterface itag = ITag.store.byId(id);
- if (itag != null && itag.isAlertDisconnected()) {
+ case disconnected:
+ if (itag != null && itag.isConnectModeEnabled()) {
statusDrawableId = R.drawable.bt_connecting;
- statusTextId = R.string.bt_lost;
+ statusDrawableTint = Color.RED;
+ statusTextId = R.string.bt_disconnected;
+ Log.d("ingo", "disconnected");
} else {
- statusDrawableId = R.drawable.bt_setup;
- if (state == BLEConnectionState.connecting)
- statusTextId = R.string.bt_connecting;
- else statusTextId = R.string.bt_disconnecting;
+ statusDrawableId = R.drawable.bt_call;
+ statusDrawableTint = Color.LTGRAY;
+ statusTextId = R.string.bt_scanning;
+ }
+ break;
+ case disconnecting:
+ case connecting:
+ progressBar = true;
+ statusDrawableId = R.drawable.bt_setup;
+ statusDrawableTint = Color.parseColor("#FFA500"); // orange
+ if (state == BLEConnectionState.connecting) {
+ statusTextId = R.string.bt_connecting;
+ } else {
+ statusTextId = R.string.bt_disconnecting;
}
break;
case writting:
@@ -241,18 +251,27 @@ private void updateState(@NonNull ViewGroup rootView, @NonNull String id, @NonNu
statusDrawableId = R.drawable.bt_call;
statusTextId = R.string.bt_call;
break;
- case disconnected:
default:
statusDrawableId = R.drawable.bt_disabled;
+ statusDrawableTint = Color.LTGRAY;
statusTextId = R.string.bt_disabled;
}
+ final ProgressBar progressBarView = rootView.findViewById(R.id.progressBar);
+ if(progressBar){
+ progressBarView.setVisibility(View.VISIBLE);
+ } else {
+ progressBarView.setVisibility(View.GONE);
+ }
} else {
statusDrawableId = R.drawable.bt_disabled;
+ statusDrawableTint = Color.LTGRAY;
statusTextId = R.string.bt_disabled;
}
-
final ImageView imgStatus = rootView.findViewById(R.id.bt_status);
imgStatus.setImageResource(statusDrawableId);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ imgStatus.getDrawable().setTint(statusDrawableTint);
+ }
final TextView textStatus = rootView.findViewById(R.id.text_status);
textStatus.setText(statusTextId);
}
@@ -265,21 +284,25 @@ private void updateState(@NonNull String id, @NonNull BLEConnectionState state)
updateState(view, id, state);
}
- private void updateName(@NonNull ViewGroup rootView, String name) {
+ private void updateName(@NonNull ViewGroup rootView, ITagInterface itag) {
Activity activity = getActivity();
if (activity == null) return; //
final TextView textName = rootView.findViewById(R.id.text_name);
- textName.setText(name);
+ final TextView textId = rootView.findViewById(R.id.text_id);
+ textName.setText(itag.name());
+ textId.setText(itag.id());
}
- private void updateAlertButton(@NonNull ViewGroup rootView, boolean isAlertDisconnected, boolean isConnected) {
+ private void updateAlertButton(@NonNull ViewGroup rootView, boolean isConnectModeEnabled, boolean isConnected) {
Activity activity = getActivity();
if (activity == null) return; //
final ImageView btnAlert = rootView.findViewById(R.id.btn_alert);
+ final TextView modeTextView = rootView.findViewById(R.id.text_mode);
if (BuildConfig.DEBUG) {
- Log.d(LT, "updateAlertButton2 isAlertDisconnected=" + isAlertDisconnected + " isConnected=" + isConnected);
+ Log.d(LT, "updateAlertButton2 isConnectModeEnabled=" + isConnectModeEnabled + " isConnected=" + isConnected);
}
- btnAlert.setImageResource(isAlertDisconnected || isConnected ? R.drawable.linked : R.drawable.keyfinder);
+ btnAlert.setImageResource(isConnectModeEnabled ? R.drawable.linked : R.drawable.keyfinder);
+ modeTextView.setText(getString(isConnectModeEnabled || isConnected ? R.string.mode_active : R.string.mode_passive));
}
private void updateAlertButton(@NonNull String id) {
@@ -304,29 +327,65 @@ private void updateAlertButton(@NonNull String id) {
}
BLEConnectionInterface connection = ble.connectionById(id);
boolean isConnected = connection.isConnected();
- boolean isAlertDisconnected = itag.isAlertDisconnected();
+ boolean isConnectModeEnabled = itag.isConnectModeEnabled();
if (BuildConfig.DEBUG) {
- Log.d(LT, "id = " + id + " updateAlertButton2 isAlertDisconnected=" + isAlertDisconnected + " isConnected=" + isConnected);
+ Log.d(LT, "id = " + id + " updateAlertButton2 isAlertDisconnected=" + isConnectModeEnabled + " isConnected=" + isConnected);
}
- updateAlertButton(view, isAlertDisconnected, isConnected);
+ updateAlertButton(view, isConnectModeEnabled, isConnected);
}
private void updateITagImageAnimation(@NonNull ViewGroup rootView, ITagInterface itag, BLEConnectionInterface connection) {
Activity activity = getActivity();
if (activity == null) return; //
- if (mITagAnimation == null) {
+ if (mITagAnimationShakeIndefinitely == null) {
return;
}
Animation animShake = null;
+ float alpha;
if (BuildConfig.DEBUG) {
- Log.d(LT, "updateITagImageAnimation isFindMe:" + connection.isFindMe() + " isAlerting:" + connection.isAlerting() + " isAlertDisconnected:" + itag.isAlertDisconnected() + " not connected:" + !connection.isConnected());
- }
- if (connection.isAlerting() || connection.isFindMe() || itag.isAlertDisconnected() && !connection.isConnected()) {
- animShake = mITagAnimation;//AnimationUtils.loadAnimation(getActivity(), R.anim.shake_itag);
+ Log.d(LT, "updateITagImageAnimation isFindMe:" + connection.isFindMe() +
+ " isAlerting:" + connection.isAlerting() +
+ " isConnectModeEnabled:" + itag.isConnectModeEnabled() +
+ " not connected:" + !connection.isConnected()
+ );
+ }
+ if (connection.isAlerting() ||
+ itag.isShaking() ||
+ connection.isFindMe()) {
+ animShake = mITagAnimationShakeIndefinitely;
+ }
+ if(connection.observableClick().value() == 1){
+ animShake = mITagAnimationShakeOnce;
+ }
+ if(connection.isConnected()){
+ alpha = 1.0f;
+ } else {
+ alpha = 0.3f;
+ }
+ final ITagImageView imageITag = rootView.findViewById(R.id.image_itag);
+ imageITag.setOnClickListener(view -> {
+ ((MainActivity) activity).onITagClick(itag);
+ });
+ imageITag.setOnLongClickListener(view -> {
+ if(connection.state() == BLEConnectionState.connected || connection.state() == BLEConnectionState.connecting) {
+ ITag.store.setReconnectMode(itag.id(), false);
+ new Thread(connection::disconnect).start();
+ } else if(connection.state() == BLEConnectionState.disconnected) {
+ ITag.store.setShakingOnConnectDisconnect(itag.id(), false);
+ connection.connect();
+ }
+ return true;
+ });
+ if (Looper.myLooper() == Looper.getMainLooper()) {
+ imageITag.setAlpha(alpha);
+ } else {
+ float finalAlpha = alpha;
+ getActivity().runOnUiThread(() -> {
+ imageITag.setAlpha(finalAlpha);
+ });
}
- final ImageView imageITag = rootView.findViewById(R.id.image_itag);
if (animShake == null) {
if (BuildConfig.DEBUG) {
Log.d(LT, "updateITagImageAnimation: No animations appointed");
@@ -346,12 +405,15 @@ private void updateITagImageAnimation(@NonNull ViewGroup rootView, ITagInterface
imageITag.startAnimation(animShake);
} else {
final Animation anim = animShake;
- getActivity().runOnUiThread(() -> imageITag.startAnimation(anim));
+ float finalAlpha = alpha;
+ getActivity().runOnUiThread(() -> {
+ imageITag.startAnimation(anim);
+ });
}
}
}
- private void updateITagImageAnimation(@NonNull ITagInterface itag, @NonNull BLEConnectionInterface connection) {
+ void updateITagImageAnimation(@NonNull ITagInterface itag, @NonNull BLEConnectionInterface connection) {
Activity activity = getActivity();
if (activity == null) return; //
ViewGroup view = tagViews.get(itag.id());
@@ -386,8 +448,7 @@ private void updateITagImage(@NonNull ViewGroup rootView, ITagInterface itag) {
break;
}
-
- final ImageView imageITag = rootView.findViewById(R.id.image_itag);
+ final ITagImageView imageITag = rootView.findViewById(R.id.image_itag);
imageITag.setImageResource(imageId);
imageITag.setTag(itag);
}
@@ -397,11 +458,14 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
// Inflate the layout for this fragment
mLocationAnimation = AnimationUtils.loadAnimation(getActivity(), R.anim.shadow_location);
- mITagAnimation = AnimationUtils.loadAnimation(getActivity(), R.anim.shake_itag);
+ mITagAnimationShakeIndefinitely = AnimationUtils.loadAnimation(getActivity(), R.anim.shake_itag_indefinitely);
+ mITagAnimationShakeOnce = AnimationUtils.loadAnimation(getActivity(), R.anim.shake_itag_once);
final VolumePreference mute = new VolumePreference(getContext());
View root = inflater.inflate(R.layout.fragment_itags, container, false);
if (root != null) {
+ ViewGroup realRoot = root.findViewById(R.id.root);
+ setupTags(realRoot);
final ImageView imgMute = root.findViewById(R.id.btn_mute);
int m = mute.get();
imgMute.setImageResource(m == VolumePreference.MUTE ? R.drawable.mute : m == VolumePreference.LOUD ? R.drawable.nomute : R.drawable.vibration);
@@ -419,7 +483,6 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
});
}
-
return root;
}
@@ -464,9 +527,12 @@ public void onResume() {
Activity activity = getActivity();
if (activity == null) return;
ITagApplication.faITagsView(ITag.store.count());
- final ViewGroup root = (ViewGroup) requireView();
- setupTags(root);
- disposableBag.add(ITag.store.observable().subscribe(event -> setupTags(root)));
+
+ disposableBag.add(ITag.store.observable().subscribe(event -> {
+ Log.d("ingo", "setupTags");
+ activity.runOnUiThread(() -> updateTags(false));
+ //setupTags(root);
+ }));
for (int i = 0; i < ITag.store.count(); i++) {
final ITagInterface itag = ITag.store.byPos(i);
if (itag == null) {
@@ -499,6 +565,7 @@ public void onResume() {
boolean wt_disabled0 = WayTodayDisabled0Preference.get(getActivity());
if (wt_disabled0) {
+ ViewGroup root = (ViewGroup) requireView();
root.findViewById(R.id.btn_waytoday).setVisibility(View.GONE);
} else {
disposableBag.add(
diff --git a/app/src/main/java/s4y/itag/ITagsService.java b/app/src/main/java/s4y/itag/ITagsService.java
index 45e023e..cc21dae 100644
--- a/app/src/main/java/s4y/itag/ITagsService.java
+++ b/app/src/main/java/s4y/itag/ITagsService.java
@@ -140,7 +140,6 @@ public void removeFromForeground() {
inForeground = false;
}
-
private static boolean createdForegroundChannel;
private static void createForegroundNotificationChannel(Context context) {
@@ -164,7 +163,8 @@ static Notification createForegroundNotification(Context context) {
builder
.setTicker(null)
.setSmallIcon(R.drawable.app)
- .setContentTitle(context.getString(R.string.service_in_background))
+ .setOngoing(true)
+ .setContentTitle(context.getString(R.string.service_in_background)) // TODO: change this texts to something like "iTag One Running..." and create icon on main activity which will open tutorial
.setContentText(context.getString(R.string.service_description));
Intent intent = new Intent(context, MainActivity.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
diff --git a/app/src/main/java/s4y/itag/MainActivity.java b/app/src/main/java/s4y/itag/MainActivity.java
index 409cef4..b2cff72 100644
--- a/app/src/main/java/s4y/itag/MainActivity.java
+++ b/app/src/main/java/s4y/itag/MainActivity.java
@@ -6,7 +6,6 @@
import android.bluetooth.BluetoothAdapter;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
-import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
@@ -31,6 +30,7 @@
import java.util.ArrayList;
import java.util.Locale;
+import java.util.Map;
import java.util.Objects;
import s4y.gps.sdk.android.GPSPermissionManager;
@@ -38,11 +38,13 @@
import s4y.gps.sdk.android.GPSUpdatesForegroundService;
import s4y.itag.ble.AlertVolume;
import s4y.itag.ble.BLEConnectionInterface;
+import s4y.itag.ble.BLEConnectionState;
import s4y.itag.ble.BLEState;
import s4y.itag.history.HistoryRecord;
import s4y.itag.itag.ITag;
import s4y.itag.itag.ITagInterface;
import s4y.itag.itag.TagColor;
+import s4y.itag.itag.TagConnectionMode;
import s4y.itag.preference.WayTodayDisabled0Preference;
import s4y.itag.preference.WayTodayFirstPreference;
import s4y.itag.waytoday.WayToday;
@@ -52,6 +54,7 @@ public class MainActivity extends FragmentActivity {
private static final int REQUEST_CODE_NOTIFICATION_PERMISSION = 123;
static public final int REQUEST_ENABLE_BT = 1;
static public final int REQUEST_ONSCAN = 2;
+ static public final int REQUEST_ENABLE_LOCATION = 3;
public ITagsService iTagsService;
public static boolean sIsShown = false;
private static final String LT = MainActivity.class.getName();
@@ -62,6 +65,9 @@ public class MainActivity extends FragmentActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
+ checkForPermissions();
+ setupContent();
+ checkIfPassiveScannerShouldTurnOn();
if (WayToday.getInstance().isTrackingOn() && !GPSPermissionManager.needPermissionRequest(this, true)) {
GPSUpdatesForegroundService.start(this);
}
@@ -81,7 +87,7 @@ protected void onNewIntent(Intent intent) {
private void setupProgressBar() {
ProgressBar pb = findViewById(R.id.progress);
- if (ITag.ble.scanner().isScanning()) {
+ if (mSelectedFragment == FragmentType.SCANNER) {
pb.setVisibility(View.VISIBLE);
pb.setIndeterminate(false);
pb.setMax(ITag.SCAN_TIMEOUT);
@@ -100,6 +106,8 @@ private enum FragmentType {
private FragmentType mSelectedFragment;
private int mEnableAttempts = 0;
+ Fragment fragment2 = null;
+
static class ITagServiceConnection implements ServiceConnection {
@Override
@@ -131,8 +139,10 @@ protected void onResume() {
// TODO: ErrorsObservable.addErrorListener(mErrorListener);
sIsShown = true;
setupContent();
- // TODO: Waytoday.gpsLocationUpdater.addOnPermissionListener(gpsPermissionListener);
- disposableBag.add(ITag.ble.observableState().subscribe(event -> setupContent()));
+ disposableBag.add(ITag.ble.observableState().subscribe(event -> {
+ setupContent();
+ checkIfPassiveScannerShouldTurnOn();
+ }));
disposableBag.add(ITag.ble.scanner().observableActive().subscribe(
event -> {
if (BuildConfig.DEBUG) {
@@ -143,7 +153,15 @@ protected void onResume() {
}
));
disposableBag.add(ITag.ble.scanner().observableTimer().subscribe(
- event -> setupProgressBar()
+ event -> {
+ if(ITag.ble.scanner().observableTimer().value() < 0){
+ newDevicesScanner = false;
+ Log.d("ingo", "gasimo scanner");
+ setupContent();
+ } else {
+ setupProgressBar();
+ }
+ }
));
disposableBag.add(ITag.store.observable().subscribe(event -> {
switch (event.op) {
@@ -178,10 +196,11 @@ protected void onPause() {
} catch (IllegalArgumentException e) {
// ignore
}
+ Log.d("ingo", "disposeamo bag");
disposableBag.dispose();
sIsShown = false;
if (!exitting) {
- if (ITag.store.isDisconnectAlert()) {
+ if (ITag.store.isDisconnectAlertOn()) {
ITagsService.start(this);
} else {
ITagsService.stop(this);
@@ -197,6 +216,7 @@ protected void onPause() {
}
private boolean mHasFocus = false;
+ private boolean newDevicesScanner = false;
@Override
public void onWindowFocusChanged(boolean hasFocus) {
@@ -218,47 +238,34 @@ protected void onSaveInstanceState(@NonNull Bundle outState) {
//No call for super(). Bug on API Level > 11. issue #54
}
- private boolean isFirstLaunch() {
- SharedPreferences sharedPref = getPreferences(Context.MODE_PRIVATE);
- return sharedPref.getBoolean("first", true);
- }
-
- private void setNotFirstLaunch() {
- SharedPreferences sharedPref = getPreferences(Context.MODE_PRIVATE);
- SharedPreferences.Editor ed = sharedPref.edit();
- ed.putBoolean("first", false);
- ed.apply();
- }
-
private void setupContent() {
- final FragmentManager fragmentManager = getSupportFragmentManager();
- final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
- Fragment fragment = null;
if (BuildConfig.DEBUG) {
Log.d(LT, "setupContent isScanning=" + ITag.ble.scanner().isScanning() + " thread=" + Thread.currentThread().getName());
}
- if (ITag.ble.scanner().isScanning()) {
- setupProgressBar();
+ Fragment newFragment = null;
+ setupProgressBar();
+ Log.d("ingo", "setupContent");
+ if (newDevicesScanner) {
+ Log.d("ingo", "scanner is scanning");
mEnableAttempts = 0;
if (mSelectedFragment != FragmentType.SCANNER) {
- fragment = new ScanFragment();
+ Log.d("ingo", "switch to scanner");
+ newFragment = new ScanFragment();
mSelectedFragment = FragmentType.SCANNER;
}
} else {
- setupProgressBar();
if (ITag.ble.state() == BLEState.NO_ADAPTER) {
- fragment = new NoBLEFragment();
+ newFragment = new NoBLEFragment();
mSelectedFragment = FragmentType.OTHER;
} else {
if (ITag.ble.state() == BLEState.OK) {
- setNotFirstLaunch();
mEnableAttempts = 0;
if (mSelectedFragment != FragmentType.ITAGS) {
- fragment = new ITagsFragment();
+ newFragment = new ITagsFragment();
mSelectedFragment = FragmentType.ITAGS;
}
} else {
- if (mEnableAttempts < 60 && isFirstLaunch()) {
+ if (mSelectedFragment == FragmentType.OTHER && mEnableAttempts < 10) { // already showing "turn on bluetooth"
mEnableAttempts++;
if (BuildConfig.DEBUG) {
Log.d(LT, "setupContent BT disabled, enable attempt=" + mEnableAttempts);
@@ -266,7 +273,7 @@ private void setupContent() {
if (mEnableAttempts == 1) {
Toast.makeText(this, R.string.try_enable_bt, Toast.LENGTH_LONG).show();
}
- ITag.ble.enable();
+ //ITag.ble.enable(); deprecated and should't do anything because bluetooth should be turned on by user action - click on "turn on bluetooth" button in fragment_ble_disabled
try {
// A bit against rules but ok in this situation
Thread.sleep(500);
@@ -278,23 +285,30 @@ private void setupContent() {
if (BuildConfig.DEBUG) {
Log.d(LT, "setupContent BT disabled, auto enable failed");
}
- fragment = new DisabledBLEFragment();
+ newFragment = new DisabledBLEFragment();
mSelectedFragment = FragmentType.OTHER;
}
}
}
}
- if (fragment != null) {
- fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
- fragmentTransaction.replace(R.id.content, fragment);
+ if (newFragment != null) {
+ final FragmentManager fragmentManager = getSupportFragmentManager();
+ final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
+ Log.d("ingo", "fragment je " + newFragment.getClass().getSimpleName() + ", mSelectedFragment je " + mSelectedFragment);
+ //fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
+ fragmentTransaction.replace(R.id.content, newFragment, null);
fragmentTransaction.commitAllowingStateLoss();
+ fragment2 = newFragment;
}
}
@Override
public void onBackPressed() {
- if (ITag.ble.scanner().isScanning()) {
+ if (mSelectedFragment == FragmentType.SCANNER && newDevicesScanner) {
ITag.ble.scanner().stop();
+ newDevicesScanner = false;
+ setupContent();
+ checkIfPassiveScannerShouldTurnOn();
} else {
super.onBackPressed();// your code.
}
@@ -371,45 +385,57 @@ public void onLocationClick(@NonNull View sender) {
}
}
- public void onITagClick(@NonNull View sender) {
- ITagInterface itag = (ITagInterface) sender.getTag();
- if (itag == null) {
- return;
- }
- MediaPlayerUtils.getInstance().stopSound(this);
+ public boolean isItagsFragmentShown(){
+ return fragment2 != null && fragment2.getClass().getSimpleName().equals("ITagsFragment");
+ }
+
+ public void onITagClick(@NonNull ITagInterface itag) {
+ Log.d("ingo", "onITagClick");
final BLEConnectionInterface connection = ITag.ble.connectionById(itag.id());
- Notifications.cancelDisconnectNotification(this);
- if (connection.isFindMe()) {
- connection.resetFindeMe();
+
+ if (connection.isFindMe()) { // iTag contacting phone
+ connection.resetFindMe();
+ } else if(itag.isShaking()) {
+ ITag.store.setShakingOnConnectDisconnect(itag.id(), false);
+ Log.d("ingo", "did it");
+ // TODO: check if fragment needs updating
+ if(isItagsFragmentShown()) {
+ Log.d("ingo", "isItagsFragmentShown true");
+ ((ITagsFragment) fragment2).updateITagImageAnimation(itag, connection);
+ }
+ Notifications.cancelDisconnectNotification(this);
+ Notifications.cancelConnectNotification(this);
+ MediaPlayerUtils.getInstance().stopSound(this);
+ } else if(!itag.isConnectModeEnabled()){
+ toggleTagConnectivity(itag);
} else if (connection.isConnected()) {
+ Log.d("ingo", "connected");
new Thread(() -> {
- if (connection.isAlerting()) {
- connection.writeImmediateAlert(AlertVolume.NO_ALERT, ITag.BLE_TIMEOUT);
- } else {
- connection.writeImmediateAlert(AlertVolume.HIGH_ALERT, ITag.BLE_TIMEOUT);
- }
+ toggleAlertOnITag(connection);
}).start();
} else {
- if (!itag.isAlertDisconnected()) {
- // there's no sense to communicate if the connection
- // in the connecting state
- ITag.connectAsync(connection, false, () -> {
- if (connection.isAlerting()) {
- connection.writeImmediateAlert(AlertVolume.NO_ALERT, ITag.BLE_TIMEOUT);
- } else {
- connection.writeImmediateAlert(AlertVolume.HIGH_ALERT, ITag.BLE_TIMEOUT);
- }
-
- });
+ Log.e("ingo", "device NOT connected and connectivity is enabled");
+ // nothing here is needed since scanner will connect to the device once the device is discovered
+ if(connection.state() != BLEConnectionState.connecting) {
+ connection.connect(); // TODO: remove this after scanner and reconnect correctly implemented
}
}
}
+ private static void toggleAlertOnITag(BLEConnectionInterface connection) {
+ if (connection.isAlerting()) {
+ connection.writeImmediateAlert(AlertVolume.NO_ALERT, ITag.BLE_TIMEOUT);
+ } else {
+ connection.writeImmediateAlert(AlertVolume.HIGH_ALERT, ITag.BLE_TIMEOUT);
+ }
+ }
+
public void onStartStopScan(View ignored) {
if (BuildConfig.DEBUG) {
Log.d(LT, "onStartStopScan isScanning=" + ITag.ble.scanner().isScanning() + " thread=" + Thread.currentThread().getName());
}
- if (ITag.ble.scanner().isScanning()) {
+ if (newDevicesScanner) {
+ newDevicesScanner = false;
ITag.ble.scanner().stop();
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
@@ -426,13 +452,22 @@ public void onStartStopScan(View ignored) {
dialog.cancel())
.show();
} else {
- // isScanRequestAbortedBecauseOfPermission=true;
requestAllPermissions(MainActivity.REQUEST_ONSCAN);
}
return;
}
}
- ITag.ble.scanner().start(ITag.SCAN_TIMEOUT, new String[]{});
+ newDevicesScanner = true;
+ ITag.ble.scanner().start(true, ITag.SCAN_TIMEOUT, new String[]{});
+ setupContent();
+ }
+ }
+
+ void checkForPermissions(){
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
+ requestAllPermissions(MainActivity.REQUEST_ENABLE_LOCATION);
+ }
}
}
@@ -459,7 +494,7 @@ public void onAppMenu(@NonNull View sender) {
popupMenu.setOnMenuItemClickListener(item -> {
if (item.getItemId() == R.id.exit) {
exitting = true;
- ITag.close();
+ ITag.closeApplication();
WayToday.getInstance().gpsUpdatesManager.stop();
ITagsService.stop(this);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
@@ -608,37 +643,49 @@ public void onChangeColor(@NonNull View sender) {
popupMenu.show();
}
- public void onDisconnectAlert(@NonNull View sender) {
+ public void connectivityButton(@NonNull View sender) {
ITagInterface itag = (ITagInterface) sender.getTag();
if (itag == null) {
ITagApplication.handleError(new Exception("No itag"));
return;
}
+ toggleTagConnectivity(itag);
+ }
+
+ public void toggleTagConnectivity(@NonNull ITagInterface itag) {
BLEConnectionInterface connection = ITag.ble.connectionById(itag.id());
- if (itag.isAlertDisconnected()) {
- ITag.store.setAlert(itag.id(), false);
+ if (itag.isConnectModeEnabled()) {
+ Log.d("ingo", "disconnectItag yes");
+ ITag.store.setConnectMode(itag.id(), TagConnectionMode.passive);
new Thread(connection::disconnect).start();
} else {
- if (connection.isConnected()) {
- new Thread(connection::disconnect).start();
- } else {
- ITag.store.setAlert(itag.id(), true);
- ITag.connectAsync(connection);
- }
+ Log.d("ingo", "disconnectItag no");
+ ITag.store.setConnectMode(itag.id(), TagConnectionMode.active);
+ Log.d("ingo", "isAlertEnabled? it should be: " + itag.isConnectModeEnabled());
+ connection.connect();
+ //ITag.connectAsync(connection);
}
- if (itag.isAlertDisconnected()) {
- Toast.makeText(this, R.string.mode_alertdisconnect, Toast.LENGTH_SHORT).show();
- ITagApplication.faUnmuteTag();
- if (GPSPermissionManager.needPermissionRequest(this, true)) {
- GPSPermissionManager.requestPermissions(this,
- getString(R.string.gps_permission_request),
- getString(R.string.gps_background_permission_request)
- );
+ checkIfPassiveScannerShouldTurnOn();
+ }
+
+ private void checkIfPassiveScannerShouldTurnOn() {
+ if(newDevicesScanner) return;
+ boolean shouldPassiveScannerBeOn = false;
+ for(Map.Entry tagEntry : ITag.store.getTagMap().entrySet()){
+ if(tagEntry.getValue().connectionMode() == TagConnectionMode.passive ||
+ (tagEntry.getValue().connectionMode() == TagConnectionMode.active && tagEntry.getValue().reconnectMode() && !ITag.ble.connectionById(tagEntry.getKey()).isConnected())
+ ){
+ Log.d("ingo", "scanner, passive is " + tagEntry.getValue().name());
+ shouldPassiveScannerBeOn = true;
+ break;
}
- checkNotificationPermission();
- } else {
- Toast.makeText(this, R.string.mode_keyfinder, Toast.LENGTH_SHORT).show();
- ITagApplication.faMuteTag();
+ }
+ if(shouldPassiveScannerBeOn && !ITag.ble.scanner().isScanning()){
+ ITag.ble.scanner().start(false, 0, new String[]{});
+ ITag.subscribePassiveScanner();
+ } else if(!shouldPassiveScannerBeOn && ITag.ble.scanner().isScanning()){
+ ITag.ble.scanner().stop();
+ ITag.unsubscribePassiveScanner();
}
}
@@ -661,6 +708,7 @@ protected void onActivityResult(int requestCode, int resultCode, @Nullable Inten
switch (requestCode) {
case REQUEST_ENABLE_BT:
setupContent();
+ Log.d("ingo", "bluetooth enabled");
break;
}
}
@@ -671,10 +719,13 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
switch (requestCode) {
case REQUEST_ENABLE_BT:
+ Log.d("ingo", "onRequestPermissionsResult REQUEST_ENABLE_BT");
setupContent();
break;
+ case REQUEST_ENABLE_LOCATION:
case REQUEST_ONSCAN:
onStartStopScan(null);
+ setupContent();
break;
}
}
@@ -701,7 +752,6 @@ public void onOpenBTSettings(View ignored) {
private void checkNotificationPermission() {
if (Build.VERSION.SDK_INT > 32) {
if (checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
- // Should we show rationale?
if (shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS)) {
new androidx.appcompat.app.AlertDialog.Builder(this)
.setTitle("Notification Permission Required")
@@ -715,7 +765,6 @@ private void checkNotificationPermission() {
.create()
.show();
} else {
- // No explanation needed, request the permission directly
requestPermissions(new String[]{Manifest.permission.POST_NOTIFICATIONS}, REQUEST_CODE_NOTIFICATION_PERMISSION);
}
}
diff --git a/app/src/main/java/s4y/itag/MediaPlayerUtils.java b/app/src/main/java/s4y/itag/MediaPlayerUtils.java
index 4cdc3c1..d8ba4bc 100644
--- a/app/src/main/java/s4y/itag/MediaPlayerUtils.java
+++ b/app/src/main/java/s4y/itag/MediaPlayerUtils.java
@@ -95,7 +95,7 @@ public void run() {
if (v == null) {
return;
}
-// Vibrate for 500 milliseconds
+ // Vibrate for 500 milliseconds
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
v.vibrate(VibrationEffect.createOneShot(500, VibrationEffect.DEFAULT_AMPLITUDE));
} else {
@@ -110,7 +110,7 @@ public boolean isSound() {
return mPlayer.isPlaying();
}
- public void startSoundDisconnected(Context context) {
+ public void startSoundConnectedDisconnected(Context context, Boolean disconnected) {
stopSound(context);
// check if we have permission get call state
@@ -133,11 +133,11 @@ public void startSoundDisconnected(Context context) {
AssetFileDescriptor afd = null;
try {
- afd = context.getAssets().openFd("lost.mp3");
-
+ afd = context.getAssets().openFd("lost.mp3"); // TODO: different sound on connect and disconnect
+ MediaPlayerUtils.getInstance().stop();
mVolumeLevel = am.getStreamVolume(AudioManager.STREAM_ALARM);
am.setStreamVolume(AudioManager.STREAM_ALARM, am.getStreamMaxVolume(AudioManager.STREAM_ALARM), 0);
-
+ // TODO: make duration of alarm configurable
mPlayer.stop();
mPlayer.reset();
mPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
@@ -146,7 +146,7 @@ public void startSoundDisconnected(Context context) {
mPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
mPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
mPlayer.prepareAsync();
- // mPlayer.start();
+ // mPlayer.start();
} catch (IOException e) {
ITagApplication.handleError(e, true);
} finally {
diff --git a/app/src/main/java/s4y/itag/Notifications.java b/app/src/main/java/s4y/itag/Notifications.java
index 22980e4..c8ade29 100644
--- a/app/src/main/java/s4y/itag/Notifications.java
+++ b/app/src/main/java/s4y/itag/Notifications.java
@@ -13,13 +13,16 @@
public class Notifications {
private static final int NOTIFICATION_DISCONNECT_ID = 2;
+ private static final int NOTIFICATION_CONNECT_ID = 3;
private static final String CHANNEL_DISCONNECT_ID = "ditag1";
+ private static final String CHANNEL_CONNECT_ID = "ditag2";
static final String EXTRA_STOP_SOUND = "stop_sound";
private static boolean createdChannelDisconnected;
+ private static boolean createdChannelConnected;
private static void createDisconnectNotificationChannel() {
if (!createdChannelDisconnected && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- CharSequence name = ITagApplication.context.getString(R.string.app_name);
+ CharSequence name = ITagApplication.context.getString(R.string.channel_disconnect);
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel channel = new NotificationChannel(CHANNEL_DISCONNECT_ID, name, importance);
channel.setSound(null, null);
@@ -33,6 +36,22 @@ private static void createDisconnectNotificationChannel() {
}
}
+ private static void createConnectNotificationChannel() {
+ if (!createdChannelConnected && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ CharSequence name = ITagApplication.context.getString(R.string.channel_connect);
+ int importance = NotificationManager.IMPORTANCE_HIGH;
+ NotificationChannel channel = new NotificationChannel(CHANNEL_CONNECT_ID, name, importance);
+ channel.setSound(null, null);
+ channel.setShowBadge(false);
+ channel.enableVibration(true);
+ NotificationManager notificationManager = ITagApplication.context.getSystemService(NotificationManager.class);
+ if (notificationManager != null) {
+ notificationManager.createNotificationChannel(channel);
+ createdChannelConnected = true;
+ }
+ }
+ }
+
// TODO: i do not understand what's is the reason of the warning to supress
@SuppressLint("LaunchActivityFromNotification")
public static void sendDisconnectNotification(Context context, String name) {
@@ -68,10 +87,46 @@ public static void sendDisconnectNotification(Context context, String name) {
}
}
+ public static void sendConnectNotification(Context context, String name) {
+ createConnectNotificationChannel();
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(context, ITagsService.FOREGROUND_CHANNEL_ID);
+ builder
+ .setTicker(String.format(context.getString(R.string.notify_connect),
+ name == null || "".equals(name) ? "iTag" : name))
+ .setSmallIcon(R.drawable.noalert)
+ .setContentTitle(String.format(context.getString(R.string.notify_connect), name))
+ .setContentText(context.getString(R.string.click_to_silent))
+ .setPriority(Notification.PRIORITY_MAX)
+ .setAutoCancel(true);
+
+ Intent intent = ITagsService.intentStart(context);
+ intent.putExtra(EXTRA_STOP_SOUND, true);
+ PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ builder.setContentIntent(pendingIntent);
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ createConnectNotificationChannel();
+ builder.setChannelId(CHANNEL_CONNECT_ID);
+ }
+ Notification notification = builder.build();
+
+ NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ if (notificationManager != null) {
+ notificationManager.notify(NOTIFICATION_CONNECT_ID, notification);
+ }
+ }
+
public static void cancelDisconnectNotification(Context context) {
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager != null) {
notificationManager.cancel(NOTIFICATION_DISCONNECT_ID);
}
}
+
+ public static void cancelConnectNotification(Context context) {
+ NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ if (notificationManager != null) {
+ notificationManager.cancel(NOTIFICATION_CONNECT_ID);
+ }
+ }
}
diff --git a/app/src/main/java/s4y/itag/RssiView.java b/app/src/main/java/s4y/itag/RssiView.java
index bde1a0d..dfb99d2 100644
--- a/app/src/main/java/s4y/itag/RssiView.java
+++ b/app/src/main/java/s4y/itag/RssiView.java
@@ -46,7 +46,7 @@ public RssiView(Context context, AttributeSet attrs, int defStyleAttr, int defSt
private View l12;
static private final float BG_ON=1f;
- static private final float BG_OFF=0.1f;
+ static private final float BG_OFF=0.3f;
public void setRssi(int level) {
// -999 indicates no signal
diff --git a/app/src/main/java/s4y/itag/ScanFragment.java b/app/src/main/java/s4y/itag/ScanFragment.java
index dc40482..276f9b0 100644
--- a/app/src/main/java/s4y/itag/ScanFragment.java
+++ b/app/src/main/java/s4y/itag/ScanFragment.java
@@ -11,7 +11,9 @@
import android.widget.TextView;
import androidx.annotation.NonNull;
+import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
+import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@@ -43,28 +45,19 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
recyclerView.setLayoutManager(layoutManager);
adapter = new Adapter();
+
+ DividerItemDecoration divider = new DividerItemDecoration(
+ requireContext(), DividerItemDecoration.VERTICAL
+ );
+ divider.setDrawable(
+ ContextCompat.getDrawable(requireContext(), R.drawable.line_divider)
+ );
+
recyclerView.setAdapter(adapter);
+ recyclerView.addItemDecoration(divider);
return view;
}
- /*
- private ListView listView() {
- View root = getView();
- if (root == null) return null;
- return root.findViewById(R.id.results_list);
- }
-
- private Adapter adapter(ListView listView) {
- if (listView == null) {
- return null;
- }
- return ((Adapter) (listView.getAdapter()));
- }
-
- private Adapter adapter() {
- return adapter(listView());
- }
- */
private long lastUpdate = 0;
@SuppressLint("NotifyDataSetChanged")
@@ -74,6 +67,7 @@ public void onResume() {
ITagApplication.faScanView(ITag.store.count() > 0);
disposableBag.add(
ITag.ble.scanner().observableScan().subscribe((result) -> {
+ // TODO: check if this is why device doesn't show up after being forgotten
if (ITag.store.remembered(result.id)) {
return;
}
@@ -187,11 +181,6 @@ public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
holder.btnRemember.setOnClickListener(onClickListener);
holder.btnRemember2.setOnClickListener(onClickListener);
- if (position % 2 == 1) {
- holder.itemView.setBackgroundColor(0xffe0e0e0);
- } else {
- holder.itemView.setBackgroundColor(Color.TRANSPARENT);
- }
holder.rssiView.setRssi(scanResult.rssi);
if (getActivity() != null && isAdded()) {
// issue #38 Fragment not attached to Activity
diff --git a/app/src/main/java/s4y/itag/SetNameDialogFragment.java b/app/src/main/java/s4y/itag/SetNameDialogFragment.java
index 181f18a..d2af343 100644
--- a/app/src/main/java/s4y/itag/SetNameDialogFragment.java
+++ b/app/src/main/java/s4y/itag/SetNameDialogFragment.java
@@ -4,10 +4,12 @@
import android.app.AlertDialog;
import android.app.Dialog;
import android.os.Bundle;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
-import android.widget.RadioButton;
-import android.widget.RadioGroup;
+import android.widget.ArrayAdapter;
+import android.widget.CheckBox;
+import android.widget.Spinner;
import android.widget.TextView;
import androidx.annotation.NonNull;
@@ -15,6 +17,8 @@
import s4y.itag.itag.ITag;
import s4y.itag.itag.ITagInterface;
+import s4y.itag.itag.TagAlertMode;
+import s4y.itag.itag.TagConnectionMode;
public class SetNameDialogFragment extends DialogFragment {
static ITagInterface iTag;
@@ -27,42 +31,90 @@ public Dialog onCreateDialog(Bundle savedInstanceState) {
@SuppressLint("InflateParams") final View view = inflater.inflate(R.layout.fragment_set_name, null);
final TextView textName = view.findViewById(R.id.text_name);
textName.setText(iTag.name());
- final RadioGroup grpAlarm = view.findViewById(R.id.alarm_delay);
- final RadioButton btnAlarm0 = view.findViewById(R.id.alarm_delay_0);
- final RadioButton btnAlarm3 = view.findViewById(R.id.alarm_delay_3);
- final RadioButton btnAlarm5 = view.findViewById(R.id.alarm_delay_5);
- final RadioButton btnAlarm10 = view.findViewById(R.id.alarm_delay_10);
- /*
- final AlarmDelayPreference alarmDelayPreference =
- new AlarmDelayPreference(this.getContext(), device);
- *
- */
- grpAlarm.clearCheck();
+
+ final CheckBox reconnect_checkbox = view.findViewById(R.id.reconnect_checkbox);
+ reconnect_checkbox.setChecked(iTag.reconnectMode());
+
+ final Spinner alarmDelaySpinner = view.findViewById(R.id.alarm_delay_spinner);
+ ArrayAdapter alarmDelayAdapter = ArrayAdapter.createFromResource(
+ requireContext(),
+ R.array.itag_alarm_delays,
+ android.R.layout.simple_spinner_item
+ );
+ alarmDelayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ alarmDelaySpinner.setAdapter(alarmDelayAdapter);
+
+ final Spinner alarmModeSpinner = view.findViewById(R.id.alarm_mode_spinner);
+ ArrayAdapter alarmModeAdapter = ArrayAdapter.createFromResource(
+ requireContext(),
+ R.array.itag_alarm_modes,
+ android.R.layout.simple_spinner_item
+ );
+ alarmModeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ alarmModeSpinner.setAdapter(alarmModeAdapter);
+
+ TagAlertMode alertMode = iTag.alertMode();
+ switch(alertMode){
+ case noAlarm:
+ alarmModeSpinner.setSelection(0);
+ break;
+ case alertOnDisconnect:
+ alarmModeSpinner.setSelection(1);
+ break;
+ case alertOnConnect:
+ alarmModeSpinner.setSelection(2);
+ break;
+ case alertOnBoth:
+ alarmModeSpinner.setSelection(3);
+ break;
+ }
+
int alarm = iTag.alertDelay();
if (alarm < 3) {
- btnAlarm0.setChecked(true);
+ alarmDelaySpinner.setSelection(0);
} else if (alarm < 5) {
- btnAlarm3.setChecked(true);
+ alarmDelaySpinner.setSelection(1);
} else if (alarm < 10) {
- btnAlarm5.setChecked(true);
+ alarmDelaySpinner.setSelection(2);
} else {
- btnAlarm10.setChecked(true);
+ alarmDelaySpinner.setSelection(3);
}
builder.setTitle(R.string.change_name)
.setView(view)
.setPositiveButton(android.R.string.ok, (dialog, id) -> {
- ITag.store.setName(iTag.id(), textName.getText().toString());
- ITagApplication.faNameITag();
- int bid = grpAlarm.getCheckedRadioButtonId();
- if (bid == R.id.alarm_delay_0) {
- ITag.store.setAlertDelay(iTag.id(), 0);
- } else if (bid == R.id.alarm_delay_3) {
- ITag.store.setAlertDelay(iTag.id(), 3);
- } else if (bid == R.id.alarm_delay_5) {
- ITag.store.setAlertDelay(iTag.id(), 5);
- } else {
- ITag.store.setAlertDelay(iTag.id(), 10);
+ if(!iTag.name().equals(textName.getText().toString())) {
+ ITag.store.setName(iTag.id(), textName.getText().toString());
+ ITagApplication.faNameITag();
+ }
+ ITag.store.setReconnectMode(iTag.id(), reconnect_checkbox.isChecked());
+ switch (alarmDelaySpinner.getSelectedItemPosition()) {
+ case 0:
+ ITag.store.setAlertDelay(iTag.id(), 0);
+ break;
+ case 1:
+ ITag.store.setAlertDelay(iTag.id(), 3);
+ break;
+ case 2:
+ ITag.store.setAlertDelay(iTag.id(), 5);
+ break;
+ default:
+ ITag.store.setAlertDelay(iTag.id(), 10);
+ break;
+ }
+ switch (alarmModeSpinner.getSelectedItemPosition()) {
+ case 0:
+ ITag.store.setAlertMode(iTag.id(), TagAlertMode.noAlarm);
+ break;
+ case 1:
+ ITag.store.setAlertMode(iTag.id(), TagAlertMode.alertOnDisconnect);
+ break;
+ case 2:
+ ITag.store.setAlertMode(iTag.id(), TagAlertMode.alertOnConnect);
+ break;
+ default:
+ ITag.store.setAlertMode(iTag.id(), TagAlertMode.alertOnBoth);
+ break;
}
})
.setNegativeButton(android.R.string.cancel, (dialog, id) -> {
diff --git a/app/src/main/java/s4y/itag/itag/ITag.java b/app/src/main/java/s4y/itag/itag/ITag.java
index 5a8b5ee..a264b66 100644
--- a/app/src/main/java/s4y/itag/itag/ITag.java
+++ b/app/src/main/java/s4y/itag/itag/ITag.java
@@ -1,6 +1,7 @@
package s4y.itag.itag;
import android.content.Context;
+import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
@@ -22,7 +23,7 @@
import s4y.itag.preference.VolumePreference;
import solutions.s4y.rasat.DisposableBag;
-import static s4y.itag.Notifications.cancelDisconnectNotification;
+import static s4y.itag.Notifications.sendConnectNotification;
import static s4y.itag.Notifications.sendDisconnectNotification;
public class ITag {
@@ -34,46 +35,78 @@ public class ITag {
private static final Map reconnectListeners = new HashMap<>();
private static final DisposableBag disposables = new DisposableBag();
+ private static final DisposableBag disposablePassiveScanner = new DisposableBag();
private static final DisposableBag disposablesConnections = new DisposableBag();
private static final Map asyncConnections = new HashMap<>();
private static final Map connectionBags = new HashMap<>();
+ private static final int PASSIVE_DISCONNECT_TIMEOUT = 2000;
+ private static final android.os.Handler passiveDisconnectTimeoutHandler = new Handler(Looper.getMainLooper());
+ private static final Map passiveDisconnectRunnables = new HashMap<>();
+ private static void iTagPassivelyDisconnected(ITagInterface itag) {
+ if(!itag.isShaking() && itag.connectionMode() == TagConnectionMode.passive) {
+ ITag.store.setPassivelyDisconnected(itag.id(), true);
+ alertUser(itag, true);
+ }
+ };
public static void initITag(Context context) {
- ble = BLEDefault.shared(context, BuildConfig.DEBUG);
store = new ITagsStoreDefault(ITagApplication.context);
- for (int i = 0; i < store.count(); i++) {
- ITagInterface itag = store.byPos(i);
- if (itag != null) {
- if (itag.isAlertDisconnected()) {
- BLEConnectionInterface connection = ITag.ble.connectionById(itag.id());
- connectAsync(connection);
- enableReconnect(itag.id());
- }
- }
+ ble = BLEDefault.shared(context, store.getIds());
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ Log.d("ingo", "dadarata");
}
- subscribeDisconnections();
+ subscribeDisconnectionsAndConnections();
disposables.add(store.observable().subscribe(event -> {
- ITagInterface itag = event.tag;
- boolean reconnect = store.remembered(itag.id()) && itag.isAlertDisconnected();
- BLEConnectionInterface connection = ble.connectionById(itag.id());
- if (reconnect) {
- enableReconnect(itag.id());
- if (!connection.isConnected()) {
- connectAsync(connection);
- }
- } else {
- disableReconnect(itag.id());
- if (connection.isConnected()) {
- new Thread(() -> connection.disconnect(BLE_TIMEOUT)).start();
- }
- }
- subscribeDisconnections();
+ Log.d("ingo", "disposables.add(store.observable().subscribe(event -> { " + event.op);
+ subscribeDisconnectionsAndConnections();
}));
+ subscribePassiveScanner();
+ }
+ public static void unsubscribePassiveScanner(){
+ disposablePassiveScanner.dispose();
}
- public static void close() {
+ public static void subscribePassiveScanner() {
+ // TODO: pass bluetooth manager only devices with passive mode ON.
+ disposablePassiveScanner.dispose();
+ disposablePassiveScanner.add(
+ ITag.ble.scanner().observableScan().subscribe((result) -> {
+ ITagInterface itag = ITag.store.byId(result.id);
+ if(itag == null) return;
+ if(itag.connectionMode() == TagConnectionMode.passive) {
+ BLEConnectionInterface connection = ITag.ble.connectionById(result.id);
+ connection.broadcastRSSI(result.rssi);
+ // to handle disconnects
+ if(itag.alertMode() == TagAlertMode.alertOnDisconnect || itag.alertMode() == TagAlertMode.alertOnBoth) {
+ Runnable runnable;
+ if (passiveDisconnectRunnables.containsKey(itag.id())) {
+ runnable = passiveDisconnectRunnables.get(itag.id());
+ } else {
+ runnable = () -> iTagPassivelyDisconnected(itag);
+ passiveDisconnectRunnables.put(itag.id(), runnable);
+ }
+ passiveDisconnectTimeoutHandler.removeCallbacks(runnable);
+ passiveDisconnectTimeoutHandler.postDelayed(runnable, PASSIVE_DISCONNECT_TIMEOUT);
+ }
+ // to handle connects
+ if(itag.alertMode() == TagAlertMode.alertOnDisconnect || itag.alertMode() == TagAlertMode.alertOnBoth) {
+ if(itag.hasPassivelyDisconnected()){
+ alertUser(itag, false);
+ ITag.store.setPassivelyDisconnected(itag.id(), false);
+ }
+ }
+ }
+ // handle reconnects for devices in active mode
+ if(itag.connectionMode() == TagConnectionMode.active && itag.reconnectMode() && ITag.ble.connectionById(itag.id()).state() == BLEConnectionState.disconnected){
+ ITag.ble.connectionById(itag.id()).connect();
+ }
+ })
+ );
+ }
+
+ public static void closeApplication() {
List ids;
synchronized (reconnectListeners) {
ids = new ArrayList<>(reconnectListeners.keySet());
@@ -103,70 +136,97 @@ public static void close() {
disposablesConnections.dispose();
}
- private static void subscribeDisconnections() {
+ private static void subscribeDisconnectionsAndConnections() {
disposablesConnections.dispose();
for (int i = 0; i < store.count(); i++) {
final ITagInterface itag = store.byPos(i);
- if (itag != null) {
- BLEConnectionInterface connection = ble.connectionById(itag.id());
- if (itag.isAlertDisconnected()){
- disposablesConnections.add(connection.observableState().subscribe(event -> {
- if (BuildConfig.DEBUG)
- Log.d(LT, "connection " + connection.id() + " state " + connection.state());
- if (itag.isAlertDisconnected() && BLEConnectionState.disconnected.equals(connection.state())) {
- if (itag.alertDelay() == 0) {
- if (BuildConfig.DEBUG)
- Log.d(LT, "connection " + connection.id() + " lost");
- MediaPlayerUtils.getInstance().startSoundDisconnected(ITagApplication.context);
- sendDisconnectNotification(ITagApplication.context, itag.name());
- HistoryRecord.add(ITagApplication.context, itag.id());
- } else {
- if (BuildConfig.DEBUG) Log.d(LT, "connection " +
- connection.id() + " lost will be delayed by " +
- (itag.alertDelay() * 1000) + "ms");
- new Handler(Looper.getMainLooper()).postDelayed(() -> {
- if (BuildConfig.DEBUG) Log.d(LT, "connection " +
- connection.id() + " lost posted, state=" +
- connection.state());
- if (itag.isAlertDisconnected() && !connection.isConnected()) {
- if (BuildConfig.DEBUG)
- Log.d(LT, "connection " + connection.id() + " lost");
- int volume = new VolumePreference(ITagApplication.context).get();
- if (volume == VolumePreference.LOUD) {
- MediaPlayerUtils.getInstance().startSoundDisconnected(ITagApplication.context);
- } else if (volume == VolumePreference.VIBRATION) {
- MediaPlayerUtils.getInstance().startVibrate();
- }
- sendDisconnectNotification(ITagApplication.context, itag.name());
- HistoryRecord.add(ITagApplication.context, itag.id());
- }
- }, itag.alertDelay() * 1000L);
- }
- } else if (BLEConnectionState.connected.equals(connection.state())) {
+ if (itag == null) continue;
+ BLEConnectionInterface connection = ble.connectionById(itag.id());
+ if (itag.isConnectModeEnabled()){
+ disposablesConnections.add(connection.observableState().subscribe(event -> {
+ if (BuildConfig.DEBUG)
+ Log.d(LT, "connection " + connection.id() + " state " + connection.state());
+ if(connection.state() == connection.oldState()){
+ return;
+ }
+ if(
+ (BLEConnectionState.connected.equals(connection.state()) && BLEConnectionState.writting.equals(connection.oldState())) ||
+ (BLEConnectionState.writting.equals(connection.state()))
+ ){
+ connection.setOldState(connection.state());
+ return;
+ }
+ connection.setOldState(connection.state());
+ if ((itag.alertMode() == TagAlertMode.alertOnDisconnect || itag.alertMode() == TagAlertMode.alertOnBoth) && BLEConnectionState.disconnected.equals(connection.state())) {
+ if (itag.alertDelay() == 0) {
if (BuildConfig.DEBUG)
- Log.d(LT, "connection " + connection.id() + " restored");
- MediaPlayerUtils.getInstance().stopSound(ITagApplication.context);
- cancelDisconnectNotification(ITagApplication.context);
- HistoryRecord.clear(ITagApplication.context, itag.id());
+ Log.d(LT, "connection " + connection.id() + " lost");
+ alertUser(itag, true);
+ connection.broadcastRSSI(-999);
+ } else {
+ if (BuildConfig.DEBUG) Log.d(LT, "connection " +
+ connection.id() + " lost will be delayed by " +
+ (itag.alertDelay() * 1000) + "ms");
+ new Handler(Looper.getMainLooper()).postDelayed(() -> {
+ if (BuildConfig.DEBUG) Log.d(LT, "connection " +
+ connection.id() + " lost posted, state=" +
+ connection.state());
+ if (itag.isConnectModeEnabled() && !connection.isConnected()) {
+ if (BuildConfig.DEBUG)
+ Log.d(LT, "connection " + connection.id() + " lost");
+ alertUser(itag, true);
+ }
+ }, itag.alertDelay() * 1000L);
+ }
+ } else if (BLEConnectionState.connected.equals(connection.state())) {
+ if (BuildConfig.DEBUG)
+ Log.d(LT, "connection " + connection.id() + " restored");
+ if((itag.alertMode() == TagAlertMode.alertOnConnect || itag.alertMode() == TagAlertMode.alertOnBoth)){
+ alertUser(itag, false);
}
}
- ));
- }
- disposablesConnections.add(connection.observableClick().subscribe(click -> {
- if (click != 0 && connection.isAlerting()) {
- new Thread(() -> connection.writeImmediateAlert(AlertVolume.NO_ALERT, ITag.BLE_TIMEOUT)).start();
+ }
+ ));
+ }
+ disposablesConnections.add(connection.observableClick().subscribe(click -> {
+ Log.d("ingo", "Clicks: " + click);
+ if (click != 0 && connection.isAlerting()) {
+ Log.d("ingo", "click first case");
+ new Thread(() -> connection.writeImmediateAlert(AlertVolume.NO_ALERT, ITag.BLE_TIMEOUT)).start();
+ } else {
+ Log.d("ingo", "click second case");
+ if (connection.isFindMe() && !MediaPlayerUtils.getInstance().isSound()) {
+ MediaPlayerUtils.getInstance().startFindPhone(ITagApplication.context);
} else {
- if (connection.isFindMe() && !MediaPlayerUtils.getInstance().isSound()) {
- MediaPlayerUtils.getInstance().startFindPhone(ITagApplication.context);
- } else {
- if (connection.isConnected()) {
- MediaPlayerUtils.getInstance().stopSound(ITagApplication.context);
- }
+ if (connection.isConnected()) {
+ stopSound();
}
}
- }));
- }
+ }
+ }));
+ }
+ }
+
+ static void stopSound(){
+ MediaPlayerUtils.getInstance().stopSound(ITagApplication.context);
+ }
+
+ private static void alertUser(ITagInterface itag, Boolean disconnected) {
+ Log.d("ingo", "setShakingOnConnectDisconnect(true)");
+ //itag.setShaking(true);
+ ITag.store.setShakingOnConnectDisconnect(itag.id(), true);
+ int volume = new VolumePreference(ITagApplication.context).get();
+ if (volume == VolumePreference.LOUD) {
+ MediaPlayerUtils.getInstance().startSoundConnectedDisconnected(ITagApplication.context, disconnected);
+ } else if (volume == VolumePreference.VIBRATION) {
+ MediaPlayerUtils.getInstance().startVibrate();
+ }
+ if(disconnected) {
+ sendDisconnectNotification(ITagApplication.context, itag.name());
+ } else {
+ sendConnectNotification(ITagApplication.context, itag.name());
}
+ HistoryRecord.add(ITagApplication.context, itag.id());
}
private static int connectThreadsCount = 0;
@@ -187,6 +247,7 @@ static void connectAsync(final BLEConnectionInterface connection, Runnable onCom
@SuppressWarnings("SameParameterValue")
public static void connectAsync(final BLEConnectionInterface connection, boolean infinity, Runnable onComplete) {
+ // TODO: this should be completely removed since we want to use bluetooth scanner to scan the device and then connect to it
synchronized (asyncConnections) {
if (asyncConnections.containsKey(connection.id())) {
return;
@@ -218,10 +279,10 @@ public void run() {
if (BuildConfig.DEBUG) {
Log.d(LT, "BLE Connect thread connect " + connection.id() + "/" + itag.name() + " " + Thread.currentThread().getName());
}
- connection.connect(infinity);
- } while (!isInterrupted() && itag.isAlertDisconnected() && infinity && !connection.isConnected());
+ connection.connect();
+ } while (!isInterrupted() && itag.isConnectModeEnabled() && infinity && !connection.isConnected());
// stop sound on connection in any case
- MediaPlayerUtils.getInstance().stopSound(ITagApplication.context);
+ stopSound();
if (!isInterrupted()) {
if (onComplete != null) {
onComplete.run();
@@ -242,20 +303,20 @@ public void run() {
thread.start();
}
- private static void enableReconnect(String id) {
+ public static void enableReconnect(String id) {
disableReconnect(id);
synchronized (reconnectListeners) {
final BLEConnectionInterface connection = ITag.ble.connectionById(id);
reconnectListeners.put(id, connection.observableState()
.subscribe(state -> {
if (BLEConnectionState.disconnected.equals(state)) {
- connectAsync(connection);
+ //connectAsync(connection);
}
}));
}
}
- private static void disableReconnect(String id) {
+ public static void disableReconnect(String id) {
synchronized (reconnectListeners) {
AutoCloseable existing = reconnectListeners.get(id);
if (existing != null) {
diff --git a/app/src/main/java/s4y/itag/itag/ITagDefault.java b/app/src/main/java/s4y/itag/itag/ITagDefault.java
index 583fe30..a645267 100644
--- a/app/src/main/java/s4y/itag/itag/ITagDefault.java
+++ b/app/src/main/java/s4y/itag/itag/ITagDefault.java
@@ -1,5 +1,7 @@
package s4y.itag.itag;
+import android.util.Log;
+
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -19,24 +21,33 @@ public class ITagDefault implements ITagInterface, Serializable {
private String name;
@NonNull
private TagColor color;
- private boolean alert;
+ private TagAlertMode alertMode;
+ private TagConnectionMode connectionMode;
private int alertDelay;
-
- public ITagDefault(@NonNull String id, @Nullable String name, @Nullable TagColor color, @Nullable Boolean alert, @Nullable Integer alertDelay) {
+ // TODO: use these two variables below to stop alerting user when unnecessary
+ boolean ignoreNextConnect = false;
+ boolean ignoreNextDisonnect = false;
+ private boolean shakingOnConnectDisconnect = false;
+ private boolean hasPassivelyDisconnected = false;
+ private boolean reconnect = true;
+
+ public ITagDefault(@NonNull String id, @Nullable String name, @Nullable TagColor color, @Nullable Boolean reconnect, @Nullable Integer alertDelay, @Nullable TagAlertMode alertMode, @Nullable TagConnectionMode connectionMode) {
this.id = id;
this.name = name == null ? ITagApplication.context.getString(R.string.unknown):name;
this.color = color == null? TagColor.black : color;
- //noinspection SimplifiableConditionalExpression
- this.alert = alert == null ? false : alert;
+ this.reconnect = reconnect == null || reconnect;
+ this.alertMode = alertMode == null ? TagAlertMode.alertOnDisconnect : alertMode;
+ this.connectionMode = connectionMode == null ? TagConnectionMode.active : connectionMode;
this.alertDelay = alertDelay == null ? 5: alertDelay;
}
public ITagDefault(@NonNull BLEScanResult scanResult) {
- this(scanResult.id, scanResult.name == null ? "" : scanResult.name.trim(), null, null, null);
+ this(scanResult.id, scanResult.name == null ? "" : scanResult.name.trim(), null, null, null, null, null);
}
public ITagDefault(@NonNull String id, Map dict) {
- this(id, (String)dict.get("name"), (TagColor)dict.get("color"), (Boolean)dict.get("alert"), (Integer)dict.get("alertDelay"));
+ this(id, (String)dict.get("name"), (TagColor)dict.get("color"), (Boolean)dict.get("reconnect"), (Integer)dict.get("alertDelay"), (TagAlertMode) dict.get("alertMode"), (TagConnectionMode) dict.get("connectionMode"));
+ Log.d("ingo", "poziva se iz dicta");
}
@NonNull
@@ -62,19 +73,58 @@ public TagColor color() {
return color;
}
+ @NonNull
+ @Override
+ public TagAlertMode alertMode() {
+ return alertMode;
+ }
+
+ @NonNull
+ @Override
+ public Boolean isShaking() {
+ return shakingOnConnectDisconnect;
+ }
+
+ @NonNull
+ @Override
+ public Boolean hasPassivelyDisconnected() {
+ return hasPassivelyDisconnected;
+ }
+
+ @NonNull
+ @Override
+ public TagConnectionMode connectionMode() {
+ return connectionMode;
+ }
+
@Override
public void setColor(@NonNull TagColor color) {
this.color = color;
}
@Override
- public boolean isAlertDisconnected() {
- return alert;
+ public void setReconnectMode(@NonNull Boolean reconnect) {
+ this.reconnect = reconnect;
+ }
+
+ @Override
+ public boolean reconnectMode() {
+ return this.reconnect;
+ }
+
+ @Override
+ public void setShaking(@NonNull Boolean shaking) {
+ this.shakingOnConnectDisconnect = shaking;
+ }
+
+ @Override
+ public void setPassivelyDisconnected(@NonNull Boolean has_disconnected) {
+ this.hasPassivelyDisconnected = has_disconnected;
}
@Override
- public void setAlertDisconnected(boolean alerting) {
- this.alert = alerting;
+ public boolean isConnectModeEnabled() {
+ return connectionMode == TagConnectionMode.active;
}
@Override
@@ -87,10 +137,20 @@ public void setAlertDelay(int alertDelay) {
this.alertDelay = alertDelay;
}
+ @Override
+ public void setAlertMode(TagAlertMode alertMode) {
+ this.alertMode = alertMode;
+ }
+
+ @Override
+ public void setConnectionMode(TagConnectionMode connectionMode) {
+ this.connectionMode = connectionMode;
+ }
+
@Override
public void copyFromTag(@NonNull ITagInterface tag) {
name = tag.name();
- alert = tag.isAlertDisconnected();
+ connectionMode = tag.connectionMode();
color = tag.color();
}
@@ -101,7 +161,7 @@ public Map toDict() {
put("id", id);
put("name", name);
put("color", color);
- put("alert", alert);
+ put("connectionMode", connectionMode);
}};
}
}
diff --git a/app/src/main/java/s4y/itag/itag/ITagFileStore.java b/app/src/main/java/s4y/itag/itag/ITagFileStore.java
index ffbffc1..4ec1b1b 100644
--- a/app/src/main/java/s4y/itag/itag/ITagFileStore.java
+++ b/app/src/main/java/s4y/itag/itag/ITagFileStore.java
@@ -61,7 +61,7 @@ static private void loadFromFile(
for (Object d : dd) {
if (d instanceof ITagDevice) {
ITagDevice td = (ITagDevice) d;
- ITagDefault tagDefault = new ITagDefault(td.addr, td.name, td.color, td.linked, null);
+ ITagDefault tagDefault = new ITagDefault(td.addr, td.name, td.color, td.linked, null, null, null);
devices.add(tagDefault);
}
}
diff --git a/app/src/main/java/s4y/itag/itag/ITagInterface.java b/app/src/main/java/s4y/itag/itag/ITagInterface.java
index 162c192..a169831 100644
--- a/app/src/main/java/s4y/itag/itag/ITagInterface.java
+++ b/app/src/main/java/s4y/itag/itag/ITagInterface.java
@@ -9,10 +9,20 @@ public interface ITagInterface {
String id();
String name();
void setName(String name);
+ Boolean isShaking();
+ Boolean hasPassivelyDisconnected();
TagColor color();
void setColor(TagColor color);
- boolean isAlertDisconnected();
- void setAlertDisconnected(boolean alerting);
+ void setShaking(Boolean currentlyShaking);
+ void setPassivelyDisconnected(Boolean has_disconnected);
+ void setAlertMode(TagAlertMode alertMode);
+ void setReconnectMode(Boolean reconnect);
+ boolean reconnectMode();
+
+ void setConnectionMode(TagConnectionMode connectionMode);
+ TagConnectionMode connectionMode();
+ TagAlertMode alertMode();
+ boolean isConnectModeEnabled();
int alertDelay();
void setAlertDelay(int alarmDelay);
void copyFromTag(ITagInterface tag);
diff --git a/app/src/main/java/s4y/itag/itag/ITagsStoreDefault.java b/app/src/main/java/s4y/itag/itag/ITagsStoreDefault.java
index cb4715a..c572389 100644
--- a/app/src/main/java/s4y/itag/itag/ITagsStoreDefault.java
+++ b/app/src/main/java/s4y/itag/itag/ITagsStoreDefault.java
@@ -62,10 +62,10 @@ synchronized public int count() {
}
@Override
- synchronized public boolean isDisconnectAlert() {
+ synchronized public boolean isDisconnectAlertOn() {
for (String id : ids) {
ITagInterface itag = tags.get(id);
- if (itag != null && itag.isAlertDisconnected()) {
+ if (itag != null && itag.isConnectModeEnabled()) {
return true;
}
}
@@ -173,12 +173,67 @@ synchronized public void setAlertDelay(@NonNull String id, int delay) {
}
@Override
- synchronized public void setAlert(@NonNull String id, boolean alert) {
+ synchronized public void setAlertMode(@NonNull String id, TagAlertMode alertMode) {
ITagInterface tag = tags.get(id);
if (tag == null) {
return;
}
- tag.setAlertDisconnected(alert);
+ tag.setAlertMode(alertMode);
+ new PreferenceTagDefault(context, tag.id()).set((ITagDefault) tag);
+ channel.broadcast(new StoreOp(StoreOpType.change, tag));
+ }
+
+ @Override
+ synchronized public void setShakingOnConnectDisconnect(@NonNull String id, Boolean shaking) {
+ ITagInterface tag = tags.get(id);
+ if (tag == null) {
+ return;
+ }
+ tag.setShaking(shaking);
+ //new PreferenceTagDefault(context, tag.id()).set((ITagDefault) tag);
+ channel.broadcast(new StoreOp(StoreOpType.change, tag));
+ }
+
+ @Override
+ synchronized public void setPassivelyDisconnected(@NonNull String id, Boolean has_disconnected) {
+ ITagInterface tag = tags.get(id);
+ if (tag == null) {
+ return;
+ }
+ tag.setPassivelyDisconnected(has_disconnected);
+ //new PreferenceTagDefault(context, tag.id()).set((ITagDefault) tag);
+ channel.broadcast(new StoreOp(StoreOpType.change, tag));
+ }
+
+ @Override
+ synchronized public void setReconnectMode(@NonNull String id, Boolean reconnect) {
+ ITagInterface tag = tags.get(id);
+ if (tag == null) {
+ return;
+ }
+ tag.setReconnectMode(reconnect);
+ //new PreferenceTagDefault(context, tag.id()).set((ITagDefault) tag);
+ channel.broadcast(new StoreOp(StoreOpType.change, tag));
+ }
+
+ @Override
+ synchronized public void setConnectionMode(@NonNull String id, TagConnectionMode connectionMode) {
+ ITagInterface tag = tags.get(id);
+ if (tag == null) {
+ return;
+ }
+ tag.setConnectionMode(connectionMode);
+ new PreferenceTagDefault(context, tag.id()).set((ITagDefault) tag);
+ channel.broadcast(new StoreOp(StoreOpType.change, tag));
+ }
+
+ @Override
+ synchronized public void setConnectMode(@NonNull String id, TagConnectionMode connectionMode) {
+ ITagInterface tag = tags.get(id);
+ if (tag == null) {
+ return;
+ }
+ tag.setConnectionMode(connectionMode);
new PreferenceTagDefault(context, tag.id()).set((ITagDefault) tag);
channel.broadcast(new StoreOp(StoreOpType.change, tag));
}
@@ -204,4 +259,14 @@ synchronized public void setName(@NonNull String id, String name) {
new PreferenceTagDefault(context, tag.id()).set((ITagDefault) tag);
channel.broadcast(new StoreOp(StoreOpType.change, tag));
}
+
+ @Override
+ synchronized public List getIds() {
+ return this.ids;
+ }
+
+ @Override
+ synchronized public Map getTagMap(){
+ return this.tags;
+ }
}
diff --git a/app/src/main/java/s4y/itag/itag/ITagsStoreInterface.java b/app/src/main/java/s4y/itag/itag/ITagsStoreInterface.java
index e760bfd..f1b6cd9 100644
--- a/app/src/main/java/s4y/itag/itag/ITagsStoreInterface.java
+++ b/app/src/main/java/s4y/itag/itag/ITagsStoreInterface.java
@@ -3,11 +3,14 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import java.util.List;
+import java.util.Map;
+
import solutions.s4y.rasat.Observable;
public interface ITagsStoreInterface {
int count();
- boolean isDisconnectAlert();
+ boolean isDisconnectAlertOn();
@NonNull
Observable observable();
@Nullable
@@ -21,7 +24,14 @@ public interface ITagsStoreInterface {
void remember(@NonNull ITagInterface tag);
boolean remembered(@NonNull String id);
void setAlertDelay(@NonNull String id,int delay);
- void setAlert(@NonNull String id,boolean alert);
+ void setAlertMode(@NonNull String id, TagAlertMode alertMode);
+ void setShakingOnConnectDisconnect(@NonNull String id, Boolean shaking);
+ void setPassivelyDisconnected(@NonNull String id, Boolean has_disconnected);
+ void setReconnectMode(@NonNull String id, Boolean reconnect);
+ void setConnectionMode(@NonNull String id, TagConnectionMode connectionMode);
+ void setConnectMode(@NonNull String id, TagConnectionMode connectionMode);
void setColor(@NonNull String id,@NonNull TagColor color);
void setName(@NonNull String id,String name);
+ List getIds();
+ Map getTagMap();
}
diff --git a/app/src/main/java/s4y/itag/itag/TagAlertMode.java b/app/src/main/java/s4y/itag/itag/TagAlertMode.java
new file mode 100644
index 0000000..dac099e
--- /dev/null
+++ b/app/src/main/java/s4y/itag/itag/TagAlertMode.java
@@ -0,0 +1,8 @@
+package s4y.itag.itag;
+
+public enum TagAlertMode {
+ noAlarm,
+ alertOnDisconnect,
+ alertOnConnect,
+ alertOnBoth
+}
diff --git a/app/src/main/java/s4y/itag/itag/TagConnectionMode.java b/app/src/main/java/s4y/itag/itag/TagConnectionMode.java
new file mode 100644
index 0000000..2eed09f
--- /dev/null
+++ b/app/src/main/java/s4y/itag/itag/TagConnectionMode.java
@@ -0,0 +1,7 @@
+package s4y.itag.itag;
+
+public enum TagConnectionMode {
+ active,
+ passive,
+ off
+}
diff --git a/app/src/main/res/anim/shake_itag.xml b/app/src/main/res/anim/shake_itag_indefinitely.xml
similarity index 100%
rename from app/src/main/res/anim/shake_itag.xml
rename to app/src/main/res/anim/shake_itag_indefinitely.xml
diff --git a/app/src/main/res/anim/shake_itag_once.xml b/app/src/main/res/anim/shake_itag_once.xml
new file mode 100644
index 0000000..8c41432
--- /dev/null
+++ b/app/src/main/res/anim/shake_itag_once.xml
@@ -0,0 +1,8 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/circular_progress_bar.xml b/app/src/main/res/drawable/circular_progress_bar.xml
new file mode 100644
index 0000000..bd3dd8e
--- /dev/null
+++ b/app/src/main/res/drawable/circular_progress_bar.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/colorwheel.xml b/app/src/main/res/drawable/colorwheel.xml
new file mode 100644
index 0000000..3af2062
--- /dev/null
+++ b/app/src/main/res/drawable/colorwheel.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/colorwheel2.xml b/app/src/main/res/drawable/colorwheel2.xml
new file mode 100644
index 0000000..f18a757
--- /dev/null
+++ b/app/src/main/res/drawable/colorwheel2.xml
@@ -0,0 +1,1103 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/delete.xml b/app/src/main/res/drawable/delete.xml
new file mode 100644
index 0000000..39a7d59
--- /dev/null
+++ b/app/src/main/res/drawable/delete.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/line_divider.xml b/app/src/main/res/drawable/line_divider.xml
new file mode 100644
index 0000000..6a925bc
--- /dev/null
+++ b/app/src/main/res/drawable/line_divider.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/minus.xml b/app/src/main/res/drawable/minus.xml
index 230c992..98d41a2 100644
--- a/app/src/main/res/drawable/minus.xml
+++ b/app/src/main/res/drawable/minus.xml
@@ -5,8 +5,8 @@
-
-
+
+
@@ -14,8 +14,8 @@
-
-
+
+
diff --git a/app/src/main/res/drawable/reconnect_off.xml b/app/src/main/res/drawable/reconnect_off.xml
new file mode 100644
index 0000000..8bb050d
--- /dev/null
+++ b/app/src/main/res/drawable/reconnect_off.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/reconnect_on.xml b/app/src/main/res/drawable/reconnect_on.xml
new file mode 100644
index 0000000..ef6b4bc
--- /dev/null
+++ b/app/src/main/res/drawable/reconnect_on.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/settings.xml b/app/src/main/res/drawable/settings.xml
new file mode 100644
index 0000000..87048a6
--- /dev/null
+++ b/app/src/main/res/drawable/settings.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index d8c89eb..e28761f 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -4,7 +4,6 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="?android:attr/colorBackground"
android:orientation="vertical"
tools:context=".MainActivity">
@@ -20,7 +19,7 @@
android:id="@+id/progress"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
- android:layout_height="6dp"
+ android:layout_height="16dp"
android:layout_gravity="center_vertical"
android:indeterminate="true" />
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_set_name.xml b/app/src/main/res/layout/fragment_set_name.xml
index 289237a..264f62c 100644
--- a/app/src/main/res/layout/fragment_set_name.xml
+++ b/app/src/main/res/layout/fragment_set_name.xml
@@ -21,12 +21,52 @@
android:inputType="textPersonName"
android:text="Name" />
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+ android:layout_height="wrap_content" />
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/itag.xml b/app/src/main/res/layout/itag.xml
index 17f2d11..1c1dcef 100644
--- a/app/src/main/res/layout/itag.xml
+++ b/app/src/main/res/layout/itag.xml
@@ -1,6 +1,7 @@
-
-
-
+ android:orientation="vertical"
+ android:layout_marginLeft="8dp">
+
+
+
-
-
@@ -58,19 +61,36 @@
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_gravity="center_horizontal"
- android:layout_weight="1"
- >
+ android:layout_weight="1">
-
+
+
+
+
+
-
+
+ android:layout_marginBottom="8dp">
+
+
+
@@ -124,7 +163,7 @@
android:layout_width="@android:dimen/app_icon_size"
android:layout_height="@android:dimen/app_icon_size"
android:contentDescription="@string/manage_alert"
- android:onClick="onDisconnectAlert"
+ android:onClick="connectivityButton"
android:src="@drawable/keyfinder" />
+ android:src="@drawable/settings" />
+ android:src="@drawable/colorwheel2" />
+ android:layout_height="match_parent"
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:context=".MainActivity">
-
-
-
-
-
-
-
+
iTag One
+ قطع الاتصال
+ روابط
لا يحتوي جهازك على محول Bluetooth
إذن المطلوبة
بدءًا من نظام Android 6.0 Marshmallow ، يتطلب النظام ترخيصًا للموقع للبحث عن أجهزة بلوتوث LE.
@@ -9,7 +11,9 @@
لقد طلبت أن يتم فصل iTag. هذا ليس خطيراً ، لن ننسى iTag وسوف تكون قادراً على الاتصال مرة أخرى مع نفس الجانب الجانب. هل تريد حقا أن تفصل iTag؟
الإعدادات
اسم
- تأخير التنبيه
+ تأخير التنبيه
+ وضع اتصال
+ وضع التنبيه
لا تؤجل
3 sec
5 sec
@@ -36,6 +40,7 @@
انقر نقرًا مزدوجًا على زر iTag للعثور على الهاتف
اضغط لفترة طويلة على صورة iTag لجعلها رنانة.
انقطع الاتصال %s
+ متصل %s
انقر لإيقاف التنبيه
اضغط لفترة طويلة للعثور على iTag
ليس لديك أجهزة iTag المتصلة حتى الآن. انقر فوق Scanbutton أعلاه لبدء البحث.
@@ -86,10 +91,12 @@
قطع
كتم الصوت
- إنذار عند فقد iTag
- الاهتزاز عند فقد iTag
- لا إنذار عند فقد iTag
+ إنذار مكبر الصوت
+ إنذار الاهتزاز
+ لا إنذار
+ وضع الباحث عن المفاتيح
+ وضع التنبيه المفقود
وضع الباحث عن المفاتيح
وضع التنبيه المفقود
توقف تتبع WayToday
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index 0979bfd..4864d93 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -1,6 +1,8 @@
iTag One
+ Desconexiones
+ Conexiones
Su dispositivo no tiene adaptador Bluetooth
Se requiere permiso
A partir de Android 6.0 Marshmallow, el sistema requiere permiso de ubicación para buscar el dispositivo Bluetooth LE.\n\nTendrá que reiniciar el proceso de escaneo después de otorgar el acceso.
@@ -9,7 +11,9 @@
Lanzando con el dedo solicitó que iTag se desconectara.\n\nEsto no es peligroso, el iTag no se olvidará y podrá volver a conectarlo con el mismo lanzamiento de lado a lado.\n\n¿Realmente desea desconectarse? iTag?
Esto no es peligroso, el iTag no se olvidará y podrás volver a conectarlo con el mismo lanzamiento de lado a lado.\n\n¿Realmente quieres desconectar el iTag?
Configuración de iTag
- Retraso de alarma
+ Retraso de alarma
+ Modo de conexión
+ Modo de alarma
Sin demora
3 sec
5 sec
@@ -36,6 +40,7 @@
Haga doble clic en el botón de iTag para encontrar el teléfono
Haga clic en la imagen de iTag para que suene la etiqueta.
%s desconectado
+ %s conectados
Haga clic para detener la alarma
Pulsación larga para encontrar el iTag
Aún no tiene dispositivos iTag conectados.\n\nHaga clic en el botón Escanear arriba para comenzar a buscar.
@@ -85,9 +90,11 @@
perdido
desconectando
Mudo
- Alarma cuando iTag perdió
- Vibración cuando iTag perdió
- Sin alarma cuando iTag perdió
+ Alarma de altavoz
+ Alarma de vibración
+ Ninguna alarma
+ Modo buscador de claves
+ Modo de alarma perdido
Modo buscador de claves
Modo de alarma perdido
Seguimiento de WayToday detenido
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index 62d7f48..b74ca45 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -1,6 +1,8 @@
iTag One
+ Déconnexions
+ Connexions
Votre appareil n\'a pas d\'adaptateur Bluetooth
Autorisation requise
À partir d\'Android 6.0 Marshmallow, le système nécessite une autorisation de localisation pour rechercher un périphérique Bluetooth LE.\nVous devrez redémarrer le processus de scan après avoir donné l\'accès.
@@ -8,8 +10,10 @@
L\'appareil sera oublié, êtes-vous sûr? Vous pourrez cependant reconnecter cet appareil et vous en souvenir à tout moment.\n\nOubliez?
Paramètres d\'iTag
En lançant votre doigt, vous avez demandé que iTag soit déconnecté. Ce n\'est pas dangereux, l\'iTag ne sera pas oublié et vous pourrez le reconnecter avec le même fling côte à côte.\n\nVoulez-vous vraiment déconnecter l\'iTag?
- Délai d\'alarme
+ Délai d\'alarme
Nom de iTag
+ Mode de connexion
+ Mode alarme
Sans délais
3 sec
5 sec
@@ -40,6 +44,7 @@
Double-cliquez sur le bouton iTag pour trouver le téléphone
Cliquez sur l\'image d\'iTag pour faire sonner l\'étiquette.
%s déconnecté
+ %s connecté
Cliquez pour arrêter l\'alarme
Appuyez longuement pour trouver l\'iTag
Vous n’avez pas encore d’appareil iTag connecté.\n\nCliquez sur le bouton Analyser ci-dessus pour lancer la recherche.
@@ -85,9 +90,11 @@
Retirez-le
Cette action supprimera et désactivera WayToday pour toujours.\n\nLa seule façon de restaurer le suivi est de supprimer et de réinstaller l\'application.
Désactiver WayToday
- Alarme quand iTag a perdu
- Vibration lorsque iTag a perdu
- Pas d\'alarme quand iTag a perdu
+ Alarme haut-parleur
+ Alarme vibrante
+ Pas d\'alarme
+ Mode de recherche de clé
+ Mode d\'alarme perdu
Mode de recherche de clé
Mode d\'alarme perdu
Arrêt du suivi WayToday
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index 8fba518..1fa0965 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -1,6 +1,8 @@
iTag One
+ Disconnessioni
+ Connessioni
Il tuo dispositivo non ha un adattatore Bluetooth
Autorizzazione richiesta
A partire da Android 6.0 Marshmallow il sistema richiede l\'autorizzazione alla localizzazione per cercare il dispositivo Bluetooth LE.\n\nDovrai riavviare il processo di scansione dopo aver concesso l\'accesso.
@@ -9,7 +11,9 @@
Lanciando con il dito hai richiesto la disconnessione di iTag.\nQuesto non è pericoloso, l\'iTag non verrà dimenticato e sarai in grado di ricollegarlo con la stessa avventura da lato a lato.\n\nVuoi davvero disconnettere iTag?
Impostazioni di iTag
Nome di iTag
- Ritardo allarme
+ Ritardo allarme
+ Modalità di connessione
+ Modalità sveglia
Nessun ritardo
3 sec
5 sec
@@ -40,6 +44,7 @@
Fare doppio clic sul pulsante di iTag per trovare il telefono
Fare clic sull\'immagine di iTag per far squillare il tag.
%s disconnesso
+ %s connesso
Fare clic per interrompere l\'allarme
Premere a lungo per trovare l\'iTag
Non hai ancora dispositivi iTag collegati.\n\nFai clic sul pulsante Scansione sopra per avviare la ricerca.
@@ -85,9 +90,11 @@
Rimuoverlo
Questa azione rimuoverà e disabiliterà WayToday per sempre.\nL\'unico modo per ripristinare il tracciamento è rimuovere e reinstallare l\'applicazione.
Disabilita WayToday
- Allarme quando iTag ha perso
- Vibrazioni quando iTag ha perso
- Nessun allarme quando iTag ha perso
+ Allarme dell\'altoparlante
+ Allarme vibrazione
+ Nessun allarme
+ Modalità ricerca chiavi
+ Modalità di allarme perso
Modalità ricerca chiavi
Modalità di allarme perso
WayToday tracking fermato
diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml
index 62364da..61a2a9b 100644
--- a/app/src/main/res/values-pt/strings.xml
+++ b/app/src/main/res/values-pt/strings.xml
@@ -1,5 +1,7 @@
+ Desconexões
+ Conexões
Seu dispositivo não tem adaptador Bluetooth
Permissão necessária
A partir do Android 6.0 Marshmallow, o sistema requer permissão de localização para fazer a varredura do dispositivo Bluetooth LE.\n\nNVocê terá que reiniciar o processo de varredura após conceder o acesso.
@@ -8,7 +10,9 @@
Acenando com o dedo, você solicitou que o iTag fosse desconectado.\n\n
Configurações de iTag
Nome do iTag
- Atraso de alarme
+ Atraso de alarme
+ Modo de conexão
+ Modo de alarme
Sem demora
3 sec
5 sec
@@ -35,6 +39,7 @@
Clique duas vezes no botão da iTag para encontrar o telefone
Clique na imagem da iTag para fazer a tag tocar.
%s desconectado
+ %s connected
Clique para parar o alarme
Pressione e segure para encontrar o iTag
Você ainda não tem nenhum dispositivo iTag conectado.\n\nClique no botão Scan acima para iniciar a busca.
@@ -84,11 +89,11 @@
perdido
desconectando
Mudo
- Alarme quando a iTag perder
- Vibração quando a iTag perdeu
- Nenhum alarme quando a iTag perdeu
- Modo localizador de chave
- Modo de alarme perdido
+ Alarme de alto-falante
+ Alarme vibratório
+ Sem alarme
+ Modo localizador de chave
+ Modo de alarme perdido
iTag One
Rastreamento WayToday parado
Incapaz de obter a posição atual devido à falta de permissões de localização
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index 89b1337..ab477ce 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -1,6 +1,8 @@
iTag One - Ключница
+ Отключения
+ Соединения
На устройстве отсутствует bluetooth
Разрешить
Начиная с версии Android 6.0 для использованию Bluetooth устройств необходимо разрешить определять местоположение.\\nВам нужно будет повторить процесс сканирования после того разрешите доступ к датчику положения.
@@ -8,7 +10,9 @@
Этот жест отключит брелок и удалит его из списка. При повторном подключении текущие настройки будут восстановлены. Продолжить отключение?
Настроить брелок
Название брелка
- Задержка тревоги
+ Задержка тревоги
+ Режим подключения
+ Режим тревоги
Отсутсвует
3 секунды
5 секунд
@@ -35,6 +39,7 @@
Двойное нажатие кнопки на брелке для поиска телефона
Один клик на изображении брелка для его поиска
%s отключен
+ %s подключено
Одно нажатие для выключения сигнала
Длинное нажатие для поиска брелка
Нет подключенных брелков. Нажмите кнопку сканирования, чтобы начать подключение.
@@ -86,10 +91,12 @@
отключение
Бесшумный режим
- Звуковой сигнал при потере брелка
- Вибрация при потере брелка
- Нет сигнала при потере брелка
+ Сигнализация динамика
+ Вибрационная сигнализация
+ Нет будильника
+ Только поиск брелка
+ Сигнализировать при утере брелка
Только поиск брелка
Сигнализировать при утере брелка
Отслеживание WayToday остановлено
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index c8a8df8..7bdfe49 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,5 +1,7 @@
iTag One
+ Disconnections
+ Connections
Your device has no Bluetooth adapter
@@ -11,12 +13,36 @@
Flinging with your finger you requested iTag to be disconnected.\nThis is not dangerous, the iTag will not be forgotten and you will be able to connect it back with the same side-to-side fling.\n\nDo you really want disconnect iTag?
iTag\'s settings
iTag\'s Name
- Alarm delay
+ Disconnect alarm delay
+ Connection mode
+
+ Alarm mode
+
+
+ - Active mode
+ - Passive mode
+
+
+
+ - No delay
+ - 3 sec
+ - 5 sec
+ - 10 sec
+
+
+
+ - No alarm
+ - Alarm when out of range
+ - Alarm when in range
+ - Alarm on both
+
+
No delay
3 sec
5 sec
10 sec
The alarm delay will prevent itag from buzzing on very short disconnection.
+
Enable/disable Alert on disconnect
Scanning for iTags…
@@ -49,6 +75,7 @@
Click iTag\'s image to make the tag to ring.
%s disconnected
+ %s connected
Click to stop alarm
Long Press to Find the iTag
@@ -59,20 +86,22 @@
You need to Enable Bluetooth manually in the Device Settings.
Turn on Bluetooth
- off
- connecting
- disconnecting
- lost
- yelling
- linked
- faint
- lost
+ Off
+ Connecting
+ Disconnecting
+ Lost
+ Reading/writing
+ Linked
+ Faint
+ Lost
+ Disconnected
+ Scanning
Last+seen+here+%d+%s+ago
Not connected
The device seems to have a problem. Anti lost feature may fail.
- It looks like your device does not have any Map location
+ It looks like your device does not have any Map location viewer
iTag One could not get exact location because GPS disabled for this application
sec
@@ -107,10 +136,12 @@
This action will remove and disable WayToday forever.\n\nThe only way to restore the tracking is removing and re-installing the application.
Disable WayToday
- Alarm when iTag lost
- Vibration when iTag lost
- No alarm when iTag lost
+ Speaker alarm
+ Vibration alarm
+ No alarm
+ Mode: Passive
+ Mode: Active
Key finder mode
Lost alarm mode
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 64ffe09..eba6355 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -1,7 +1,7 @@
-
diff --git a/itagble/build.gradle b/itagble/build.gradle
index f267dfd..e4dfed7 100644
--- a/itagble/build.gradle
+++ b/itagble/build.gradle
@@ -7,6 +7,10 @@ android {
compileSdk 34
+ buildFeatures {
+ buildConfig = true
+ }
+
defaultConfig {
minSdkVersion 23 // due to mad-location-manager
targetSdkVersion 34
@@ -25,8 +29,6 @@ android {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
- // implementation 'androidx.appcompat:appcompat:1.2.0'
- // implementation 'solutions.s4y.rasat:rasat-android:1.0.3'
implementation "com.github.s4ysolutions:rasat-android:1.0.5"
implementation 'androidx.annotation:annotation:1.8.0'
implementation 'org.apache.commons:commons-math3:3.6.1'
diff --git a/itagble/src/main/java/s4y/itag/ble/BLECentralManagerDefault.java b/itagble/src/main/java/s4y/itag/ble/BLECentralManagerDefault.java
index e897954..e4cb0da 100644
--- a/itagble/src/main/java/s4y/itag/ble/BLECentralManagerDefault.java
+++ b/itagble/src/main/java/s4y/itag/ble/BLECentralManagerDefault.java
@@ -3,24 +3,35 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
+import android.bluetooth.le.ScanCallback;
+import android.bluetooth.le.ScanFilter;
+import android.bluetooth.le.ScanResult;
+import android.bluetooth.le.ScanSettings;
import android.content.Context;
+import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import androidx.annotation.NonNull;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import static android.bluetooth.BluetoothProfile.GATT;
import static android.bluetooth.BluetoothProfile.STATE_CONNECTED;
+import static android.bluetooth.le.ScanSettings.MATCH_MODE_AGGRESSIVE;
+import static android.bluetooth.le.ScanSettings.SCAN_MODE_BALANCED;
+import static android.bluetooth.le.ScanSettings.SCAN_MODE_LOW_LATENCY;
import com.google.firebase.crashlytics.FirebaseCrashlytics;
class BLECentralManagerDefault implements BLECentralManagerInterface, AutoCloseable {
private static final String L = BLECentralManagerDefault.class.getName();
private final Context context;
+ private final List devices_ids;
private final HandlerThread operationsThread = new HandlerThread("BLE Central Manager operations");
private final Handler operationsHandler;
private final Map scanned = new HashMap<>();
@@ -28,9 +39,13 @@ class BLECentralManagerDefault implements BLECentralManagerInterface, AutoClosea
private final Boolean debug;
private final BLECentralManagerObservables observables = new BLECentralManagerObservables();
- private final BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() {
+
+ private final ScanCallback scanCallback = new ScanCallback() {
@Override
- public void onLeScan(BluetoothDevice bluetoothDevice, int rssi, byte[] data) {
+ public void onScanResult(int callbackType, ScanResult result) {
+ super.onScanResult(callbackType, result);
+ BluetoothDevice bluetoothDevice = result.getDevice();
+ int rssi = result.getRssi();
if (debug) {
Log.d(L, "onLeScan address=" + bluetoothDevice.getAddress() + " rsss=" + rssi + " thread=" + Thread.currentThread().getName());
}
@@ -46,14 +61,24 @@ public void onLeScan(BluetoothDevice bluetoothDevice, int rssi, byte[] data) {
.observablePeripheralDiscovered
.broadcast(new BLEDiscoveryResult(
peripheral,
- rssi,
- data
+ rssi
));
}
+
+ @Override
+ public void onBatchScanResults(List results) {
+ super.onBatchScanResults(results);
+ }
+
+ @Override
+ public void onScanFailed(int errorCode) {
+ super.onScanFailed(errorCode);
+ }
};
BLECentralManagerDefault(Context context, Boolean debug) {
this.context = context;
+ this.devices_ids = new ArrayList<>();
operationsThread.start();
this.debug = debug;
operationsHandler = new Handler(operationsThread.getLooper());
@@ -113,21 +138,41 @@ public boolean isScanning() {
return adapter != null && isScanning;
}
- public void startScan() {
+ public void startScanForNewDevices(){
+ startScan(true);
+ }
+
+ public void startScan(boolean newDevices) {
+ // TODO: For apps targeting Build.VERSION_CODES#S or or higher, this requires the Manifest.permission#BLUETOOTH_SCAN permission which can be gained with Activity.requestPermissions(String[], int).
scanned.clear();
BluetoothAdapter adapter = getAdapter();
if (debug) {
Log.d(L,"startLeScan, thread="+Thread.currentThread().getName()+", adapter="+(adapter==null?"null":"not null"));
}
- if (adapter != null) {
- if (!isScanning(adapter)) {
- try {
- adapter.startLeScan(leScanCallback);
- isScanning = true;
- }catch (SecurityException e) {
- FirebaseCrashlytics.getInstance().recordException(e);
+ if (adapter == null || adapter.getBluetoothLeScanner() == null) return;
+ if (isScanning(adapter)) return;
+ try {
+ ScanSettings.Builder scanSettings = new ScanSettings.Builder();
+ if(!newDevices) {
+ List scanFilters = new ArrayList<>();
+ for(String device_id : devices_ids){
+ ScanFilter scanFilter = new ScanFilter.Builder().setDeviceAddress(device_id).build();
+ scanFilters.add(scanFilter);
+ }
+ scanSettings.setScanMode(SCAN_MODE_BALANCED);
+ scanSettings.setReportDelay(500);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ scanSettings.setMatchMode(MATCH_MODE_AGGRESSIVE);
}
+ adapter.getBluetoothLeScanner().startScan(scanFilters, scanSettings.build(), scanCallback);
+ } else {
+ scanSettings.setScanMode(SCAN_MODE_LOW_LATENCY);
+ scanSettings.setReportDelay(0);
+ adapter.getBluetoothLeScanner().startScan(new ArrayList<>(), scanSettings.build(), scanCallback);
}
+ isScanning = true;
+ } catch (SecurityException e) {
+ FirebaseCrashlytics.getInstance().recordException(e);
}
}
@@ -139,11 +184,10 @@ public void stopScan() {
}
if (isScanning(adapter)) {
try {
- adapter.stopLeScan(leScanCallback);
+ adapter.getBluetoothLeScanner().stopScan(scanCallback);
} catch (SecurityException exception) {
FirebaseCrashlytics.getInstance().recordException(exception);
- }catch (NullPointerException ignored) {
-
+ } catch (NullPointerException ignored) {
}
isScanning = false;
}
diff --git a/itagble/src/main/java/s4y/itag/ble/BLECentralManagerInterface.java b/itagble/src/main/java/s4y/itag/ble/BLECentralManagerInterface.java
index b543669..94be2f9 100644
--- a/itagble/src/main/java/s4y/itag/ble/BLECentralManagerInterface.java
+++ b/itagble/src/main/java/s4y/itag/ble/BLECentralManagerInterface.java
@@ -5,7 +5,8 @@
import androidx.annotation.NonNull;
interface BLECentralManagerInterface {
- void startScan();
+ void startScanForNewDevices();
+ void startScan(boolean newDevices);
boolean isScanning();
void stopScan();
boolean canScan();
diff --git a/itagble/src/main/java/s4y/itag/ble/BLEConnectionDefault.java b/itagble/src/main/java/s4y/itag/ble/BLEConnectionDefault.java
index 30d2e80..8445b9b 100644
--- a/itagble/src/main/java/s4y/itag/ble/BLEConnectionDefault.java
+++ b/itagble/src/main/java/s4y/itag/ble/BLEConnectionDefault.java
@@ -38,7 +38,8 @@ class BLEConnectionDefault implements BLEConnectionInterface {
private final Channel clickChannel = new Channel<>(0);
private final ChannelDistinct stateChannel = new ChannelDistinct<>(BLEConnectionState.disconnected);
private final ChannelDistinct rssiChannel = new ChannelDistinct<>(-999);
-
+ BLEConnectionState oldState = null;
+
private final Boolean debug;
@Override
@@ -134,11 +135,17 @@ private void setPeripheral(@Nullable BLEPeripheralInterace peripheral) {
}
@Override
- public BLEError connect(boolean infinity) {
+ public void connect(){
+ new Thread(() -> {
+ connectOnMainThread();
+ }).start();
+ }
+
+ public BLEError connectOnMainThread() {
clickChannel.broadcast(0);
alertChannel.broadcast(AlertVolume.NO_ALERT);
- manager.stopScan();
+ //manager.stopScan();
if (isConnected()) {
if (peripheral() == null) {
Log.w("LT", "isConnected but peripheral is null");
@@ -164,18 +171,8 @@ public BLEError connect(boolean infinity) {
BLEError error = waitForScan();
// waitForScan will set the peripheral if can
if (peripheral() == null) {
- if (infinity) {
- if (debug) Log.d(LT, "Scan failed no peripheral, will try again");
- try {
- //noinspection BusyWait
- Thread.sleep(10000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- } else {
- if (debug) Log.d(LT, "Scan failed no peripheral, will abort");
- return BLEError.ok.equals(error) ? BLEError.noPeripheral : error;
- }
+ if (debug) Log.d(LT, "Scan failed no peripheral, will abort");
+ return BLEError.ok.equals(error) ? BLEError.noPeripheral : error;
} else {
if (debug) Log.d(LT, "Scan got peripheral, will connect");
}
@@ -183,7 +180,7 @@ public BLEError connect(boolean infinity) {
// connect as soon as a peripheral scanned
if (debug) Log.d(LT, "Attempt to connect. Scan run: " + (scan ? "yes" : "no"));
- BLEError error = waitForConnect(infinity);
+ BLEError error = waitForConnect();
if (!BLEError.ok.equals(error) || !isConnected()) {
if (debug) Log.d(LT, "Attempt to connect failed");
stateChannel.broadcast(BLEConnectionState.disconnected);
@@ -268,7 +265,7 @@ private void assertPeripheral() {
private final ThreadWait monitorConnect = new ThreadWait<>();
@SuppressWarnings("UnusedReturnValue")
- private BLEError waitForConnect(boolean auto) {
+ private BLEError waitForConnect() {
if (peripheral() == null)
return BLEError.noPeripheral;
@@ -301,7 +298,7 @@ private BLEError waitForConnect(boolean auto) {
if (debug) {
Log.d(LT, "Start wait for connect " + Thread.currentThread().getName());
}
- monitorConnect.waitFor(() -> peripheral().connect(auto), auto ? 0 : 35);
+ monitorConnect.waitFor(() -> peripheral().connect(), 0);
Log.d(LT, "End wait for connect");
disposables.dispose();
if (isConnected()) {
@@ -390,13 +387,13 @@ private BLEError waitForScan() {
.subscribe((event) -> {
if (event.peripheral != null) {
if (id.equals(event.peripheral.identifier())) {
- manager.stopScan();
+ manager.stopScan(); // TODO: check if this is why the scanner stops unexpectedly
monitorScan.setPayload(event.peripheral);
}
}
})
);
- monitorScan.waitFor(manager::startScan, 25);
+ monitorScan.waitFor(manager::startScanForNewDevices, 25);
manager.stopScan();
if (monitorScan.isTimedOut()) {
return BLEError.timeout;
@@ -417,6 +414,7 @@ private class ClickHandler {
synchronized (this) {
c = count;
count = 0;
+ if(c == 1) return;
}
clickChannel.broadcast(c);
};
@@ -428,25 +426,17 @@ private synchronized void inc() {
synchronized void handleClick() {
clickHandler.removeCallbacks(BLEConnectionDefault.this.clickHandler.waitNext);
inc();
+ if(count == 1) clickChannel.broadcast(1);
Log.d(LT, "ClickHandler.handleClick postDelayed");
clickHandler.postDelayed(BLEConnectionDefault.this.clickHandler.waitNext, CLICK_INTERVAL);
}
}
- @Override
- public BLEError connect() {
- return connect(true);
- }
-
@Override
public BLEError disconnect(int timeoutSec) {
clickChannel.broadcast(0);
alertChannel.broadcast(AlertVolume.NO_ALERT);
- if (manager.isScanning()) {
- manager.stopScan();
- }
-
if (BLEConnectionState.disconnected.equals(state())) {
return BLEError.ok;
}
@@ -484,6 +474,7 @@ public BLEError disconnect(int timeoutSec) {
);
monitorDisconnect.waitFor(() -> peripheral().disconnect(), timeoutSec);
if (monitorDisconnect.isTimedOut()) {
+ Log.d("ingo", "ble disconnect timeout");
return BLEError.timeout;
}
lastStatus = monitorDisconnect.payload();
@@ -587,6 +578,11 @@ public Observable observableRSSI() {
return rssiChannel.observable;
}
+ @Override
+ public void broadcastRSSI(int rssi) {
+ rssiChannel.broadcast(rssi);
+ }
+
@Override
public Observable observableState() {
return stateChannel.observable;
@@ -608,6 +604,16 @@ public BLEConnectionState state() {
return stateChannel.observable.value();
}
+ @Override
+ public BLEConnectionState oldState() {
+ return oldState;
+ }
+
+ @Override
+ public void setOldState(BLEConnectionState oldState){
+ this.oldState = oldState;
+ }
+
@Override
public boolean isAlerting() {
return alertChannel.observable.value() != AlertVolume.NO_ALERT;
@@ -619,7 +625,7 @@ public boolean isFindMe() {
}
@Override
- public void resetFindeMe() {
+ public void resetFindMe() {
clickChannel.broadcast(0);
}
diff --git a/itagble/src/main/java/s4y/itag/ble/BLEConnectionInterface.java b/itagble/src/main/java/s4y/itag/ble/BLEConnectionInterface.java
index e354e86..e5305b8 100644
--- a/itagble/src/main/java/s4y/itag/ble/BLEConnectionInterface.java
+++ b/itagble/src/main/java/s4y/itag/ble/BLEConnectionInterface.java
@@ -14,19 +14,21 @@ public interface BLEConnectionInterface extends AutoCloseable {
String id();
boolean isConnected();
boolean isDisconnected();
- BLEError connect() throws InterruptedException;
+ void connect();
BLEError disconnect(int timeout);
BLEError disconnect();
- BLEError connect(boolean infinity);
BLEError writeImmediateAlert(AlertVolume volume, int timeout);
BLEError writeImmediateAlert(AlertVolume volume);
void enableRSSI();
void disableRSSI();
+ void broadcastRSSI(int rssi);
boolean rssiEnabled();
int rssi();
int getLastStatus();
BLEConnectionState state();
+ void setOldState(BLEConnectionState oldState);
+ BLEConnectionState oldState();
boolean isAlerting();
boolean isFindMe();
- void resetFindeMe();
+ void resetFindMe();
}
diff --git a/itagble/src/main/java/s4y/itag/ble/BLEDefault.java b/itagble/src/main/java/s4y/itag/ble/BLEDefault.java
index a0fe9cc..d84be58 100644
--- a/itagble/src/main/java/s4y/itag/ble/BLEDefault.java
+++ b/itagble/src/main/java/s4y/itag/ble/BLEDefault.java
@@ -9,7 +9,9 @@
import androidx.annotation.NonNull;
+import java.util.Collection;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import solutions.s4y.rasat.ChannelDistinct;
@@ -19,14 +21,14 @@ public class BLEDefault implements BLEInterface {
private static final String LT = BLEDefault.class.getName();
private static BLEInterface _shared;
- public static BLEInterface shared(Context context, Boolean debug) {
+ public static BLEInterface shared(Context context, List devices_ids) {
if (_shared == null) {
_shared = new BLEDefault(
context,
new BLEConnectionFactoryDefault(),
- new BLECentralManagerDefault(context, debug),
+ new BLECentralManagerDefault(context, BuildConfig.DEBUG),
new BLEScannerFactoryDefault(),
- debug
+ BuildConfig.DEBUG
);
}
return _shared;
diff --git a/itagble/src/main/java/s4y/itag/ble/BLEDiscoveryResult.java b/itagble/src/main/java/s4y/itag/ble/BLEDiscoveryResult.java
index 4fad87d..2e1d369 100644
--- a/itagble/src/main/java/s4y/itag/ble/BLEDiscoveryResult.java
+++ b/itagble/src/main/java/s4y/itag/ble/BLEDiscoveryResult.java
@@ -3,11 +3,9 @@
class BLEDiscoveryResult {
public final BLEPeripheralInterace peripheral;
public final int rssi;
- public final byte[] data;
- BLEDiscoveryResult(BLEPeripheralInterace peripheral, int rssi, byte[] data) {
+ BLEDiscoveryResult(BLEPeripheralInterace peripheral, int rssi) {
this.peripheral = peripheral;
this.rssi = rssi;
- this.data = data;
}
}
diff --git a/itagble/src/main/java/s4y/itag/ble/BLEPeripheralDefault.java b/itagble/src/main/java/s4y/itag/ble/BLEPeripheralDefault.java
index ed006a2..847e26b 100644
--- a/itagble/src/main/java/s4y/itag/ble/BLEPeripheralDefault.java
+++ b/itagble/src/main/java/s4y/itag/ble/BLEPeripheralDefault.java
@@ -64,7 +64,7 @@ public void run() {
Log.d(LT, "RSSI runnable id=" + identifier() + " isConnected=" + isConnected());
}
if (gatt() != null && isConnected()) {
- Log.v(LT, "request RSSI id=" + identifier());
+ //Log.v(LT, "request RSSI id=" + identifier());
gatt().readRemoteRssi();
}
manager.postOperation(this, RSSI_INTERVAL_MS);
@@ -92,6 +92,10 @@ public String identifier() {
@Override
+ public void connect() {
+ connect(false);
+ }
+
public void connect(boolean auto) {
if (debug) {
Log.d(LT, "connect id=" + identifier());
@@ -105,10 +109,11 @@ public void connect(boolean auto) {
}
setState(BLEPeripheralState.connecting);
BluetoothGatt g;
+ Log.e("ingo", "poveži");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- g = device.connectGatt(context, auto, callback, TRANSPORT_LE);
+ g = device.connectGatt(context, false, callback, TRANSPORT_LE);
} else {
- g = device.connectGatt(context, auto, callback);
+ g = device.connectGatt(context, false, callback);
}
if (debug) {
Log.d(LT, "init gatt id=" + identifier() + " gatt is null: " + (g == null ? "yes" : "no") + " id=" + identifier());
@@ -116,7 +121,7 @@ public void connect(boolean auto) {
if (g == null) {
Log.w(LT, "will init gatt to null, id=" + identifier());
}
- // TODO: it aready should be set in onConnectionStateChange but just in case
+ // TODO: it already should be set in onConnectionStateChange but just in case
if (g != null) {
setGatt(g);
}
@@ -138,10 +143,13 @@ public void onConnectionStateChange(@NonNull BluetoothGatt gatt, int status, int
setState(BLEPeripheralState.connected);
observables.channelConnected.broadcast(new BLEPeripheralObservablesInterface.ConnectedEvent());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
+ Log.d("ingo", "first");
waitForClose();
}
} else {
+ // if status isn't GATT_SUCCESS, it means that connect/disconnect operation failed, possibly due to network problems.
gatt.disconnect();
+ Log.d("ingo", "second");
waitForClose();
}
}
@@ -159,7 +167,7 @@ public void onServicesDiscovered(@NonNull final BluetoothGatt gatt, int status)
}
services = new BLEService[serviceList.size()];
serviceList.toArray(services);
- setState(BLEPeripheralState.discovered);
+ setState(BLEPeripheralState.services_discovered);
observables.channelDiscoveredServices.broadcast(new BLEPeripheralObservablesInterface.DiscoveredServicesEvent(services, status));
}
diff --git a/itagble/src/main/java/s4y/itag/ble/BLEPeripheralInterace.java b/itagble/src/main/java/s4y/itag/ble/BLEPeripheralInterace.java
index 860456b..7a092ba 100644
--- a/itagble/src/main/java/s4y/itag/ble/BLEPeripheralInterace.java
+++ b/itagble/src/main/java/s4y/itag/ble/BLEPeripheralInterace.java
@@ -10,7 +10,7 @@ interface BLEPeripheralInterace extends AutoCloseable {
BLEPeripheralObservablesInterface observables();
- void connect(boolean auto);
+ void connect();
void disconnect();
void discoveryServices();
BLEError writeInt8(BLECharacteristic characteristic, int value);
diff --git a/itagble/src/main/java/s4y/itag/ble/BLEPeripheralState.java b/itagble/src/main/java/s4y/itag/ble/BLEPeripheralState.java
index 5a4b574..7f36778 100644
--- a/itagble/src/main/java/s4y/itag/ble/BLEPeripheralState.java
+++ b/itagble/src/main/java/s4y/itag/ble/BLEPeripheralState.java
@@ -5,7 +5,7 @@ enum BLEPeripheralState {
connecting,
connected,
discovering,
- discovered,
+ services_discovered,
disconnecting,
writting,
}
diff --git a/itagble/src/main/java/s4y/itag/ble/BLEScannerDefault.java b/itagble/src/main/java/s4y/itag/ble/BLEScannerDefault.java
index 066e80e..e78b1bd 100644
--- a/itagble/src/main/java/s4y/itag/ble/BLEScannerDefault.java
+++ b/itagble/src/main/java/s4y/itag/ble/BLEScannerDefault.java
@@ -65,20 +65,21 @@ public Observable observableActive() {
private final DisposableBag disposableBag = new DisposableBag();
@Override
- public void start(int timeout, String[] forceCancelIds) {
+ public void start(boolean newDevices, int timeout, String[] forceCancelIds) {
stop();
if (!manager.canScan())
return;
- // resultList.add(result);
disposableBag.add(
manager.observables().observablePeripheralDiscovered().subscribe(
event -> channelScan.broadcast(new BLEScanResult(event.peripheral.address(), event.peripheral.name(), event.rssi))
));
setScanning(true);
- manager.startScan();
- channelTimer.broadcast(timeout);
+ manager.startScan(true);
+ if(timeout != 0) {
+ channelTimer.broadcast(timeout);
+ handlerTimer.postDelayed(runnableTimer, 1000);
+ }
channelActive.broadcast(true);
- handlerTimer.postDelayed(runnableTimer, 1000);
}
@Override
diff --git a/itagble/src/main/java/s4y/itag/ble/BLEScannerInterface.java b/itagble/src/main/java/s4y/itag/ble/BLEScannerInterface.java
index 324ba3b..f4daa79 100644
--- a/itagble/src/main/java/s4y/itag/ble/BLEScannerInterface.java
+++ b/itagble/src/main/java/s4y/itag/ble/BLEScannerInterface.java
@@ -8,6 +8,6 @@ public interface BLEScannerInterface {
Observable observableScan();
Observable observableActive();
- void start(int timeout, String[] forceCancelIds);
+ void start(boolean newDevices, int timeout, String[] forceCancelIds);
void stop();
}