Created
July 17, 2018 01:25
-
-
Save jackyshan/c5dea6986bf77ac764191db88ca6ec66 to your computer and use it in GitHub Desktop.
Android寻找行李
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.baitrading.bes.ui; | |
import android.os.Bundle; | |
import android.text.InputType; | |
import android.util.Log; | |
import android.view.View; | |
import android.view.animation.Animation; | |
import android.view.animation.AnimationUtils; | |
import android.view.animation.LinearInterpolator; | |
import android.widget.ImageView; | |
import android.widget.TextView; | |
import com.baitrading.bes.AppConfig; | |
import com.baitrading.bes.Constant; | |
import com.baitrading.bes.R; | |
import com.baitrading.bes.SyncUtil; | |
import com.baitrading.bes.common.LLog; | |
import com.baitrading.bes.common.OttoBus; | |
import com.baitrading.bes.common.events.BleOptEvent; | |
import com.baitrading.bes.common.events.RssiUpdateEvent; | |
import com.baitrading.bes.entity.AntiLostSettings; | |
import com.baitrading.bes.ui.view.InfoDialog; | |
import com.baitrading.bes.ui.view.TitleBar; | |
import com.baitrading.bes.util.Prefs; | |
import com.qmuiteam.qmui.widget.dialog.QMUIDialog; | |
import com.squareup.otto.Subscribe; | |
import com.suke.widget.SwitchButton; | |
import org.angmarch.views.NiceSpinner; | |
import java.text.DecimalFormat; | |
import java.util.Arrays; | |
import java.util.LinkedList; | |
import java.util.List; | |
import java.util.Timer; | |
import java.util.TimerTask; | |
import butterknife.BindView; | |
import butterknife.ButterKnife; | |
/** | |
* @author Administrator | |
*/ | |
public class LuggageGuardActivity extends BaseActivity { | |
public static final String TAG = LuggageGuardActivity.class.getSimpleName(); | |
private static final String DOT = "."; | |
@BindView(R.id.distance_state_img) | |
ImageView distanceStateImg; | |
@BindView(R.id.finding_state_txt) | |
TextView findingStateTxt; | |
@BindView(R.id.anti_lost_level_spinner) | |
NiceSpinner antiLostLevelSpinner; | |
@BindView(R.id.alarm_mode_spinner) | |
NiceSpinner alarmModeSpinner; | |
@BindView(R.id.help_center_view) | |
View helpCenterView; | |
@BindView(R.id.distance_txt) | |
TextView distanceTxt; | |
@BindView(R.id.anti_lost_txt) | |
TextView antiLostTxt; | |
@BindView(R.id.title_bar) | |
TitleBar titleBar; | |
@BindView(R.id.search_switch) | |
SwitchButton mSearchSwitch; | |
@BindView(R.id.luggage_guard_switch) | |
SwitchButton mLuggageGuardSwitch; | |
private Animation operatingAnim; | |
/** | |
* 最后一次读取到的 rssi ,用以比较来发现远近的变化 | |
*/ | |
private int lastRSSI; | |
/** | |
* 根据 rssi 查找设备,变远还是走近 | |
*/ | |
private boolean isSearching = false; | |
/** | |
* 防丢失使能状态,根据 rssi 算出距离 | |
*/ | |
private boolean antiLostEnable = false; | |
/** | |
* 正在读取 rssi ,查找设备 或 防丢失,其中一个功能开启了,则这个是正在读取 | |
*/ | |
private boolean readingRssi; | |
private Timer mReadRssiTimer; | |
private int antiLostLevel; | |
private int alarmType; | |
private InfoDialog alertDialog; | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_luggage_guard); | |
ButterKnife.bind(this); | |
OttoBus.getInstance().register(this); | |
titleBar.setOnTitleBarClickListener(new TitleBar.OnTitleBarClickListener() { | |
@Override | |
public void onLeftClick() { | |
onBackPressed(); | |
} | |
@Override | |
public void onTitleClick() { | |
} | |
@Override | |
public void onRightClick() { | |
} | |
}); | |
operatingAnim = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.alpha_distance_scan); | |
operatingAnim.setInterpolator(new LinearInterpolator()); | |
final List<String> levelSet = new LinkedList<>(Arrays.asList("Low", "Normal", "High")); | |
antiLostLevelSpinner.attachDataSource(levelSet); | |
antiLostLevelSpinner.addOnItemClickListener((parent, view, position, id) -> { | |
// 调节防丢失的灵敏度 | |
AntiLostSettings.setAntiLostLevel(getApplicationContext(), position); | |
}); | |
final List<String> modeSet = new LinkedList<>(Arrays.asList(getString(R.string.vibrate_only), getString(R.string.alarm_only), getString(R.string.vibrate_and_alarm))); | |
alarmModeSpinner.attachDataSource(modeSet); | |
alarmModeSpinner.addOnItemClickListener((parent, view, position, id) -> { | |
AntiLostSettings.setAntiLostAlarmType(getApplicationContext(), position); | |
}); | |
mSearchSwitch.setOnCheckedChangeListener((view, isChecked) -> { | |
// 点击按钮切换搜索状态 | |
isSearching = isChecked; | |
if (isSearching) { | |
// 开启搜索功能,如果当前没有在读取 rssi ,那么开启之 | |
if (!readingRssi) { | |
startReadRssi(); | |
} | |
} else { | |
// 关闭搜索设备功能,如果此时没有开启防丢失,那么就不再需要读取 rssi,关闭之 | |
if (!antiLostEnable) { | |
stopReadRssi(); | |
} | |
} | |
}); | |
mLuggageGuardSwitch.setOnCheckedChangeListener((view, isChecked) -> { | |
antiLostEnable = isChecked; | |
Prefs.with(getApplicationContext()).writeBoolean(Constant.KEY_ANTI_LOST_ALARM_ENABLE, antiLostEnable); | |
if (antiLostEnable) { | |
// 开启防丢失功能,如果此时没有在读取 rssi ,则开启之 | |
Log.d(TAG, "允许了 anti lost"); | |
if (!readingRssi) { | |
startReadRssi(); | |
} | |
} else { | |
// 关闭防丢失功能,如果当前是没有在搜索设备,那么关闭之 | |
Log.d(TAG, "禁止了 anti lost"); | |
if (!isSearching) { | |
readRssiCount = 0; | |
rssiTotal = 0; | |
stopReadRssi(); | |
} | |
} | |
}); | |
} | |
@Override | |
protected void onResume() { | |
super.onResume(); | |
// 是否已经开启了防丢失 | |
antiLostEnable = Prefs.with(getApplicationContext()).readBoolean(Constant.KEY_ANTI_LOST_ALARM_ENABLE, false); | |
mLuggageGuardSwitch.setChecked(antiLostEnable); | |
antiLostLevel = AntiLostSettings.getAntiLostLevel(getApplicationContext()); | |
antiLostLevelSpinner.setSelectedIndex(antiLostLevel); | |
alarmType = AntiLostSettings.getAntiLostAlarmType(getApplicationContext()); | |
alarmModeSpinner.setSelectedIndex(alarmType); | |
mSearchSwitch.setChecked(isSearching); | |
// 两个功能中, 有一个开启了,那就开启读取 rssi | |
if (isSearching || antiLostEnable) { | |
startReadRssi(); | |
} | |
distanceNormal(); | |
} | |
@Override | |
public void onPause() { | |
super.onPause(); | |
} | |
@Override | |
public void onStop() { | |
super.onStop(); | |
} | |
@Override | |
public void onDestroy() { | |
super.onDestroy(); | |
stopReadRssi(); | |
OttoBus.getInstance().unregister(this); | |
} | |
private void startReadRssi() { | |
if (AppConfig.isDebug) { | |
toast("startReadRssi"); | |
} | |
// 开始读取 rssi ,发送指令让设备不再休眠 | |
SyncUtil.currentNoSleep = true; | |
OttoBus.getInstance().post(new BleOptEvent(BleOptEvent.SEND_COMMAND)); | |
readingRssi = true; | |
if (mReadRssiTimer != null) { | |
mReadRssiTimer.cancel(); | |
} | |
mReadRssiTimer = new Timer(); | |
mReadRssiTimer.schedule(new ReadRssiTask(), 1000, 100); | |
} | |
private void stopReadRssi() { | |
if (AppConfig.isDebug) { | |
toast("stopReadRssi"); | |
} | |
// 可以休眠了 | |
readRssiCount = 0; | |
rssiTotal = 0; | |
SyncUtil.currentNoSleep = false; | |
OttoBus.getInstance().post(new BleOptEvent(BleOptEvent.SEND_COMMAND)); | |
readingRssi = false; | |
if (mReadRssiTimer != null) { | |
mReadRssiTimer.cancel(); | |
} | |
distanceNormal(); | |
} | |
public class ReadRssiTask extends TimerTask { | |
@Override | |
public void run() { | |
runOnUiThread(() -> { | |
OttoBus.getInstance().post(new BleOptEvent(BleOptEvent.READ_RSSI)); | |
}); | |
} | |
} | |
@Subscribe | |
public void onRssiUpdateListener(RssiUpdateEvent event) { | |
rssiUpdate(event.getRssi()); | |
} | |
/** | |
* 当前读取了多少次 rssi | |
*/ | |
private int readRssiCount = 0; | |
/** | |
* 读取周期内的 rssi 总和 | |
*/ | |
private int rssiTotal = 0; | |
/** | |
* 读取几次为一个统计周期 | |
*/ | |
private int readPeriod = 15; | |
public void rssiUpdate(int rssi) { | |
// 累加 | |
readRssiCount += 1; | |
rssiTotal += rssi; | |
if (readRssiCount % readPeriod != 0) { | |
// 没到一个周期,不处理 | |
return; | |
} else { | |
// 累计够了次数,则计算平均 rssi ,并清 0 rssiTotal | |
rssi = rssiTotal / readPeriod; | |
rssiTotal = 0; | |
// 记录第一次统计的 RSSI,设置为 A 值,用于计算距离 | |
if (readRssiCount < 19) { | |
SyncUtil.RSSI_A = Math.abs(rssi); | |
LLog.e("RSSI_A=", SyncUtil.RSSI_A + ""); | |
} | |
} | |
// 计算距离 | |
double distance = getDistance(rssi); | |
// 格式化打印日志 | |
DecimalFormat df = new DecimalFormat("#.00"); | |
String d = df.format(distance); | |
if (d.startsWith(DOT)) { | |
d = "0" + d; | |
} | |
LLog.e(TAG, "rssi:" + rssi + " ; distance: " + d + "m"); | |
// 如果开启了距离搜索 | |
if (isSearching) { | |
// 两次变化的 rssi 超过 5 才会有比较的意义 | |
if (Math.abs(Math.abs(rssi) - Math.abs(lastRSSI)) > 5) { | |
if (Math.abs(rssi) > Math.abs(lastRSSI)) { | |
distanceFarther(); | |
} else { | |
distanceCloser(); | |
} | |
// 将上一次有效的比较值,作为上一次的值,用于下次比较 | |
lastRSSI = rssi; | |
} | |
} | |
// 开启了防丢失 | |
if (antiLostEnable) { | |
// 判断距离,作出告警 | |
int antiLostLevel = AntiLostSettings.getAntiLostLevel(getApplicationContext()); | |
int antiLostDistance = AntiLostSettings.getDistanceByLevel(antiLostLevel); | |
if (distance > antiLostDistance) { | |
LLog.e(TAG, "防丢失告警"); | |
if (alertDialog != null && alertDialog.isShowing()) { | |
Log.d(TAG, "正在 alarm,不再显示第二次"); | |
return; | |
} | |
toast("Luggage Guard"); | |
showNotification(getApplicationContext(), "Luggage Guard", "Check your Luggage"); | |
if (alarmModeSpinner.getSelectedIndex() == 0) { | |
vibrate(4); | |
} else if (alarmModeSpinner.getSelectedIndex() == 1) { | |
ringStart(); | |
SyncUtil.currentFmqLongBuzzer = true; | |
} else { | |
vibrate(4); | |
ringStart(); | |
SyncUtil.currentFmqLongBuzzer = true; | |
} | |
// 长鸣告警 | |
OttoBus.getInstance().post(new BleOptEvent(BleOptEvent.SEND_COMMAND)); | |
SyncUtil.currentFmqLongBuzzer = false; | |
alertDialog = new InfoDialog(this); | |
alertDialog.show(); | |
alertDialog.setTitleTxt("ALERT"); | |
alertDialog.setMessageTxt("Check Your Luggage"); | |
alertDialog.setInfoImg(R.drawable.ic_dialog_lost); | |
alertDialog.setCenterClickListener("Close", v -> { | |
alertDialog.dismiss(); | |
if (alarmModeSpinner.getSelectedIndex() == 0) { | |
vibrateStop(); | |
} else if (alarmModeSpinner.getSelectedIndex() == 1) { | |
ringStop(); | |
} else { | |
vibrateStop(); | |
ringStop(); | |
} | |
SyncUtil.currentFmqLongBuzzer = false; | |
OttoBus.getInstance().post(new BleOptEvent(BleOptEvent.SEND_COMMAND)); | |
mLuggageGuardSwitch.setChecked(false); | |
}); | |
} | |
} | |
} | |
/** | |
* RSSI 转成距离:米 | |
* | |
* @param rssi | |
* @return 距离/米 | |
*/ | |
private double getDistance(int rssi) { | |
double distance = 0; | |
double absRSSI = Math.abs(rssi); | |
double a = SyncUtil.RSSI_A; | |
double n = SyncUtil.RSSI_n; | |
double pow = (absRSSI - a) / (10 * n); | |
distance = Math.pow(10, pow); | |
return distance; | |
} | |
private void distanceNormal() { | |
distanceStateImg.setVisibility(View.INVISIBLE); | |
findingStateTxt.setText(""); | |
} | |
private void distanceCloser() { | |
distanceStateImg.setVisibility(View.VISIBLE); | |
distanceStateImg.setImageResource(R.drawable.ic_closer); | |
distanceStateImg.setAnimation(operatingAnim); | |
operatingAnim.start(); | |
findingStateTxt.setText(""); | |
} | |
private void distanceFarther() { | |
distanceStateImg.setVisibility(View.VISIBLE); | |
distanceStateImg.setImageResource(R.drawable.ic_farther); | |
distanceStateImg.setAnimation(operatingAnim); | |
operatingAnim.start(); | |
findingStateTxt.setText(""); | |
} | |
public void changeA(View view) { | |
final QMUIDialog.EditTextDialogBuilder builder = new QMUIDialog.EditTextDialogBuilder(this); | |
builder.setTitle("当前 A 值") | |
.setPlaceholder("A") | |
.setInputType(InputType.TYPE_CLASS_NUMBER) | |
.addAction("cancel", (dialog, index) -> dialog.dismiss()) | |
.addAction("ok", (dialog, index) -> { | |
CharSequence text = builder.getEditText().getText(); | |
if (text != null && text.length() > 0) { | |
try { | |
float a = Float.parseFloat(text.toString()); | |
SyncUtil.RSSI_A = a; | |
dialog.dismiss(); | |
} catch (NumberFormatException e) { | |
toast("must input number"); | |
} | |
} else { | |
toast("year can't empty"); | |
} | |
}) | |
.show(); | |
builder.getEditText().setText(SyncUtil.RSSI_A + ""); | |
} | |
public void changeN(View view) { | |
final QMUIDialog.EditTextDialogBuilder builder = new QMUIDialog.EditTextDialogBuilder(this); | |
builder.setTitle("当前 n 值") | |
.setPlaceholder("n") | |
.setInputType(InputType.TYPE_CLASS_NUMBER) | |
.addAction("cancel", (dialog, index) -> dialog.dismiss()) | |
.addAction("ok", (dialog, index) -> { | |
CharSequence text = builder.getEditText().getText(); | |
if (text != null && text.length() > 0) { | |
try { | |
float n = Float.parseFloat(text.toString()); | |
SyncUtil.RSSI_n = n; | |
dialog.dismiss(); | |
} catch (NumberFormatException e) { | |
toast("must input number"); | |
} | |
} else { | |
toast("year can't empty"); | |
} | |
}) | |
.show(); | |
builder.getEditText().setText(SyncUtil.RSSI_n + ""); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment