forked from community/device-mgt-plugins
commit
b30aadc438
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.wso2.carbon.iot.android.sense.beacon;
|
||||
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.util.Log;
|
||||
import agent.sense.android.iot.carbon.wso2.org.wso2_senseagent.R;
|
||||
|
||||
import org.altbeacon.beacon.BeaconConsumer;
|
||||
import org.altbeacon.beacon.BeaconManager;
|
||||
import org.altbeacon.beacon.MonitorNotifier;
|
||||
import org.altbeacon.beacon.Region;
|
||||
|
||||
public class BeaconDetactorService extends Service implements BeaconConsumer {
|
||||
|
||||
private BeaconManager iBeaconManager = BeaconManager.getInstanceForApplication(this);
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent arg0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
|
||||
new Thread(){
|
||||
@Override
|
||||
public void run() {
|
||||
iBeaconManager.bind(BeaconDetactorService.this);
|
||||
}
|
||||
}.start();
|
||||
|
||||
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
|
||||
final Handler handler = new Handler();
|
||||
final Runnable runnable = new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
//stopSelf();
|
||||
}
|
||||
};
|
||||
handler.postDelayed(runnable, 10000);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
iBeaconManager.unbind(this);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBeaconServiceConnect() {
|
||||
iBeaconManager.setMonitorNotifier(new MonitorNotifier() {
|
||||
@Override
|
||||
public void didEnterRegion(Region region) {
|
||||
Log.e("BeaconDetactorService", "didEnterRegion");
|
||||
generateNotification(BeaconDetactorService.this, region.getUniqueId()
|
||||
+ ": just saw this iBeacon for the first time");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didExitRegion(Region region) {
|
||||
Log.e("BeaconDetactorService", "didExitRegion");
|
||||
generateNotification(BeaconDetactorService.this, region.getUniqueId() + ": is no longer visible");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didDetermineStateForRegion(int state, Region region) {
|
||||
Log.e("BeaconDetactorService", "didDetermineStateForRegion:" + state);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
try {
|
||||
iBeaconManager.startMonitoringBeaconsInRegion(new Region("myMonitoringUniqueId", null, null, null));
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Issues a notification to inform the user that server has sent a message.
|
||||
*/
|
||||
private static void generateNotification(Context context, String message) {
|
||||
|
||||
Intent launchIntent = new Intent(context, MonitoringActivity.class).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||
| Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
|
||||
((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)).notify(
|
||||
0,
|
||||
new NotificationCompat.Builder(context).setWhen(System.currentTimeMillis())
|
||||
.setSmallIcon(R.drawable.beacon).setTicker(message)
|
||||
.setContentTitle(context.getString(R.string.app_name)).setContentText(message)
|
||||
.setContentIntent(PendingIntent.getActivity(context, 0, launchIntent, 0)).setAutoCancel(true)
|
||||
.build());
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.wso2.carbon.iot.android.sense.beacon;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
public class BeaconScanedData {
|
||||
|
||||
|
||||
private int beaconMajor;// Major
|
||||
private int beaconMinor;//Minor
|
||||
private String beaconProximity;// Proximity
|
||||
private int beaconUuid;// Uuid
|
||||
private long timestamp;// Timestamp
|
||||
|
||||
BeaconScanedData(int beaconMajor, int beaconMinor,String beaconProximity,int beaconUuid) {
|
||||
this.beaconMajor = beaconMajor;
|
||||
this.beaconMinor = beaconMinor;
|
||||
this.beaconProximity = beaconProximity;
|
||||
this.beaconUuid = beaconUuid;
|
||||
timestamp = new Date().getTime();
|
||||
|
||||
}
|
||||
|
||||
public int getBeaconMajor() {
|
||||
return beaconMajor;
|
||||
}
|
||||
|
||||
public void setBeaconMajor(int beaconMajor) {
|
||||
this.beaconMajor = beaconMajor;
|
||||
}
|
||||
|
||||
public int getBeaconMinor() {
|
||||
return beaconMinor;
|
||||
}
|
||||
|
||||
public void setBeaconMinor(int beaconMinor) {
|
||||
this.beaconMinor = beaconMinor;
|
||||
}
|
||||
|
||||
public String getBeaconProximity() {
|
||||
return beaconProximity;
|
||||
}
|
||||
|
||||
public void setBeaconProximity(String beaconProximity) {
|
||||
this.beaconProximity = beaconProximity;
|
||||
}
|
||||
|
||||
public int getBeaconUuid() {
|
||||
return beaconUuid;
|
||||
}
|
||||
|
||||
public void setBeaconUuid(int beaconUuid) {
|
||||
this.beaconUuid = beaconUuid;
|
||||
}
|
||||
|
||||
public long getTimeStamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimeStamp(long timeStamp) {
|
||||
timestamp = timeStamp;
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package org.wso2.carbon.iot.android.sense.beacon;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import org.altbeacon.beacon.BeaconConsumer;
|
||||
import org.altbeacon.beacon.BeaconManager;
|
||||
/*
|
||||
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
public class BeaconServiceUtility {
|
||||
|
||||
private Context context;
|
||||
private PendingIntent pintent;
|
||||
private AlarmManager alarm;
|
||||
private Intent iService;
|
||||
|
||||
public BeaconServiceUtility(Context context) {
|
||||
super();
|
||||
this.context = context;
|
||||
iService = new Intent(context, BeaconDetactorService.class);
|
||||
alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
pintent = PendingIntent.getService(context, 0, iService, 0);
|
||||
}
|
||||
|
||||
public void onStart(BeaconManager iBeaconManager, BeaconConsumer consumer) {
|
||||
|
||||
stopBackgroundScan();
|
||||
iBeaconManager.bind(consumer);
|
||||
|
||||
}
|
||||
|
||||
public void onStop(BeaconManager iBeaconManager, BeaconConsumer consumer) {
|
||||
|
||||
iBeaconManager.unbind(consumer);
|
||||
startBackgroundScan();
|
||||
|
||||
}
|
||||
|
||||
private void stopBackgroundScan() {
|
||||
|
||||
alarm.cancel(pintent);
|
||||
context.stopService(iService);
|
||||
}
|
||||
|
||||
private void startBackgroundScan() {
|
||||
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.add(Calendar.SECOND, 2);
|
||||
alarm.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 360000, pintent); // 6*60 * 1000
|
||||
context.startService(iService);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,252 @@
|
||||
/*
|
||||
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.wso2.carbon.iot.android.sense.beacon;
|
||||
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
import android.view.LayoutInflater;
|
||||
import android.widget.BaseAdapter;
|
||||
import org.altbeacon.beacon.BeaconConsumer;
|
||||
import org.altbeacon.beacon.BeaconManager;
|
||||
import org.altbeacon.beacon.Beacon;
|
||||
import org.altbeacon.beacon.RangeNotifier;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import org.altbeacon.beacon.BeaconParser;
|
||||
import org.altbeacon.beacon.MonitorNotifier;
|
||||
import org.altbeacon.beacon.Region;
|
||||
import org.wso2.carbon.iot.android.sense.beacon.BeaconScanedData;
|
||||
import org.wso2.carbon.iot.android.sense.util.SenseDataHolder;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.logging.Handler;
|
||||
import agent.sense.android.iot.carbon.wso2.org.wso2_senseagent.R;
|
||||
|
||||
public class MonitoringActivity extends Activity implements BeaconConsumer {
|
||||
protected static final String TAG = MonitoringActivity.class.getName();
|
||||
private static final int PERMISSION_REQUEST_COARSE_LOCATION = 1;
|
||||
private ListView list = null;
|
||||
private BeaconAdapter adapter;
|
||||
private ArrayList<Beacon> arrayL = new ArrayList<>();
|
||||
private LayoutInflater inflater;
|
||||
|
||||
private BeaconServiceUtility beaconUtill = null;
|
||||
private BeaconManager iBeaconManager = BeaconManager.getInstanceForApplication(this);
|
||||
|
||||
BeaconScanedData beaconData;
|
||||
|
||||
@Override
|
||||
public void onBeaconServiceConnect() {
|
||||
|
||||
iBeaconManager.setBackgroundMode(true);
|
||||
|
||||
|
||||
iBeaconManager.setRangeNotifier(new RangeNotifier() {
|
||||
@Override
|
||||
public void didRangeBeaconsInRegion(Collection<Beacon> iBeacons, Region region) {
|
||||
for (Beacon beacon: iBeacons) {
|
||||
Log.i(TAG, "This beacon has identifiers:"+beacon.getId1()+", "+beacon.getId2()+", "+beacon.getId3());
|
||||
|
||||
|
||||
}
|
||||
|
||||
arrayL.clear();
|
||||
arrayL.addAll(iBeacons);
|
||||
//adapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
iBeaconManager.setMonitorNotifier(new MonitorNotifier() {
|
||||
@Override
|
||||
public void didEnterRegion(Region region) {
|
||||
Log.e("BeaconDetactorService", "didEnterRegion");
|
||||
// logStatus("I just saw an iBeacon for the first time!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didExitRegion(Region region) {
|
||||
Log.e("BeaconDetactorService", "didExitRegion");
|
||||
// logStatus("I no longer see an iBeacon");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void didDetermineStateForRegion(int state, Region region) {
|
||||
Log.e("BeaconDetactorService", "didDetermineStateForRegion");
|
||||
// logStatus("I have just switched from seeing/not seeing iBeacons: " + state);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
try {
|
||||
iBeaconManager.startRangingBeaconsInRegion(new Region("myRangingUniqueId", null, null, null));
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
iBeaconManager.startMonitoringBeaconsInRegion(new Region("myMonitoringUniqueId", null, null, null));
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_monitor);
|
||||
beaconUtill = new BeaconServiceUtility(this);
|
||||
list = (ListView) findViewById(R.id.list);
|
||||
adapter = new BeaconAdapter();
|
||||
list.setAdapter(adapter);
|
||||
inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
|
||||
//iBeaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("m:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25"));
|
||||
iBeaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));
|
||||
|
||||
iBeaconManager.bind(this);
|
||||
|
||||
iBeaconManager.setRangeNotifier(new RangeNotifier() {
|
||||
@Override
|
||||
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
|
||||
for(Beacon beacon : beacons) {
|
||||
Log.d(TAG, "UUID:" + beacon.getId1() + ", major:" + beacon.getId2() + ", minor:" + beacon.getId3() + ", Distance:" + beacon.getDistance() + ",RSSI" + beacon.getRssi() + ", TxPower" + beacon.getTxPower());
|
||||
}
|
||||
arrayL.clear();
|
||||
arrayL.addAll(beacons);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
beaconUtill.onStart(iBeaconManager, this);
|
||||
beaconUtill = new BeaconServiceUtility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
beaconUtill.onStop(iBeaconManager, this);
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
|
||||
private class BeaconAdapter extends BaseAdapter {
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
if (arrayL != null && arrayL.size() > 0)
|
||||
return arrayL.size();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Beacon getItem(int arg0) {
|
||||
return arrayL.get(arg0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int arg0) {
|
||||
return arg0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
try {
|
||||
ViewHolder holder;
|
||||
|
||||
if (convertView != null) {
|
||||
holder = (ViewHolder) convertView.getTag();
|
||||
} else {
|
||||
holder = new ViewHolder(convertView = inflater.inflate(R.layout.tupple_monitoring, null));
|
||||
}
|
||||
holder.beacon_uuid.setText("UUID: " + arrayL.get(position).getId1().toString().toUpperCase());
|
||||
|
||||
holder.beacon_major.setText("Major: " + arrayL.get(position).getId2());
|
||||
|
||||
holder.beacon_minor.setText(" Minor: " + arrayL.get(position).getId3());
|
||||
|
||||
double proximity = arrayL.get(position).getDistance();
|
||||
holder.beacon_proximity.setText("Proximity: " + (new BigDecimal(proximity).setScale(5, BigDecimal.ROUND_HALF_UP).doubleValue()));
|
||||
|
||||
holder.beacon_rssi.setText(" Rssi: " + arrayL.get(position).getRssi());
|
||||
|
||||
holder.beacon_txpower.setText(" TxPower: " + arrayL.get(position).getTxPower());
|
||||
|
||||
holder.beacon_range.setText("" + arrayL.get(position).getDistance());
|
||||
|
||||
beaconData = new BeaconScanedData(arrayL.get(position).getId2().toInt(), arrayL.get(position).getId3().toInt(),holder.beacon_uuid.toString(),arrayL.get(position).getRssi());
|
||||
SenseDataHolder.getBeaconScanedDataHolder().add(beaconData);
|
||||
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return convertView;
|
||||
}
|
||||
|
||||
private class ViewHolder {
|
||||
private TextView beacon_uuid;
|
||||
private TextView beacon_major;
|
||||
private TextView beacon_minor;
|
||||
private TextView beacon_proximity;
|
||||
private TextView beacon_rssi;
|
||||
private TextView beacon_txpower;
|
||||
private TextView beacon_range;
|
||||
|
||||
|
||||
public ViewHolder(View view) {
|
||||
beacon_uuid = (TextView) view.findViewById(R.id.BEACON_uuid);
|
||||
beacon_major = (TextView) view.findViewById(R.id.BEACON_major);
|
||||
beacon_minor = (TextView) view.findViewById(R.id.BEACON_minor);
|
||||
beacon_proximity = (TextView) view.findViewById(R.id.BEACON_proximity);
|
||||
beacon_rssi = (TextView) view.findViewById(R.id.BEACON_rssi);
|
||||
beacon_txpower = (TextView) view.findViewById(R.id.BEACON_txpower);
|
||||
beacon_range = (TextView) view.findViewById(R.id.BEACON_range);
|
||||
|
||||
|
||||
view.setTag(this);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.wso2.carbon.iot.android.sense.bmonitor;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.widget.ListView;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import agent.sense.android.iot.carbon.wso2.org.wso2_senseagent.R;
|
||||
import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice;
|
||||
import uk.co.alt236.easycursor.objectcursor.EasyObjectCursor;
|
||||
|
||||
public class BeaconMonitoringActivity extends AppCompatActivity {
|
||||
|
||||
private BluetoothLeScanner mScanner;
|
||||
private BluetoothUtils mBluetoothUtils;
|
||||
private LeDeviceListAdapter mLeDeviceListAdapter;
|
||||
private BluetoothLeDeviceStore mDeviceStore;
|
||||
|
||||
protected ListView mList;
|
||||
|
||||
public static final int MINIMUM_DISTANCE = -70;
|
||||
|
||||
public static Map itemMap;
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_beacon_monitoring);
|
||||
|
||||
itemMap = new HashMap<String, String>();
|
||||
itemMap.put("DC:5F:BD:68:88:D5", "Noodles");
|
||||
itemMap.put("EF:0F:50:D5:BA:A1", "Vegetables");
|
||||
itemMap.put("FA:F2:CF:84:C2:F7", "Oil");
|
||||
|
||||
mList = (ListView) this.findViewById(android.R.id.list);
|
||||
|
||||
mDeviceStore = new BluetoothLeDeviceStore();
|
||||
mBluetoothUtils = new BluetoothUtils(this);
|
||||
mScanner = new BluetoothLeScanner(mLeScanCallback, mBluetoothUtils);
|
||||
startScan();
|
||||
}
|
||||
|
||||
private final BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
|
||||
@Override
|
||||
public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) {
|
||||
final BluetoothLeDevice deviceLe = new BluetoothLeDevice(device, rssi, scanRecord, System.currentTimeMillis());
|
||||
if(deviceLe!= null && deviceLe.getName()!= null && !deviceLe.getName().equals("Unknown Device")){
|
||||
mDeviceStore.addDevice(deviceLe);
|
||||
|
||||
if(deviceLe.getRssi() > MINIMUM_DISTANCE){
|
||||
Object[] objects = new Object[4];
|
||||
objects[0] = deviceLe.getName();
|
||||
objects[1] = deviceLe.getAddress();
|
||||
objects[2] = deviceLe.getRssi();
|
||||
objects[3] = itemMap.get(device.getAddress());
|
||||
|
||||
new SendToSiddi().execute(objects);
|
||||
}
|
||||
|
||||
|
||||
final EasyObjectCursor<BluetoothLeDevice> c = mDeviceStore.getDeviceCursor();
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mLeDeviceListAdapter.swapCursor(c);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private void startScan() {
|
||||
|
||||
mLeDeviceListAdapter = new LeDeviceListAdapter(this, mDeviceStore.getDeviceCursor());
|
||||
mList.setAdapter(mLeDeviceListAdapter);
|
||||
|
||||
final boolean mIsBluetoothOn = mBluetoothUtils.isBluetoothOn();
|
||||
final boolean mIsBluetoothLePresent = mBluetoothUtils.isBluetoothLeSupported();
|
||||
mBluetoothUtils.askUserToEnableBluetoothIfNeeded();
|
||||
if (mIsBluetoothOn && mIsBluetoothLePresent) {
|
||||
mScanner.scanLeDevice(-1, true);
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class SendToSiddi extends AsyncTask<Object, Object, Void>{
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Object... objects) {
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,193 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.wso2.carbon.iot.android.sense.bmonitor;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice;
|
||||
import uk.co.alt236.bluetoothlelib.device.beacon.BeaconType;
|
||||
import uk.co.alt236.bluetoothlelib.device.beacon.BeaconUtils;
|
||||
import uk.co.alt236.bluetoothlelib.device.beacon.ibeacon.IBeaconDevice;
|
||||
import uk.co.alt236.bluetoothlelib.util.ByteUtils;
|
||||
import uk.co.alt236.easycursor.objectcursor.EasyObjectCursor;
|
||||
|
||||
public class BluetoothLeDeviceStore {
|
||||
private final Map<String, BluetoothLeDevice> mDeviceMap;
|
||||
|
||||
|
||||
public BluetoothLeDeviceStore() {
|
||||
mDeviceMap = new HashMap<>();
|
||||
}
|
||||
|
||||
public void addDevice(final BluetoothLeDevice device) {
|
||||
if (mDeviceMap.containsKey(device.getAddress())) {
|
||||
mDeviceMap.get(device.getAddress()).updateRssiReading(device.getTimestamp(), device.getRssi());
|
||||
} else {
|
||||
mDeviceMap.put(device.getAddress(), device);
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
mDeviceMap.clear();
|
||||
}
|
||||
|
||||
public EasyObjectCursor<BluetoothLeDevice> getDeviceCursor() {
|
||||
return new EasyObjectCursor<>(
|
||||
BluetoothLeDevice.class,
|
||||
getDeviceList(),
|
||||
"address");
|
||||
}
|
||||
|
||||
public List<BluetoothLeDevice> getDeviceList() {
|
||||
final List<BluetoothLeDevice> methodResult = new ArrayList<>(mDeviceMap.values());
|
||||
|
||||
Collections.sort(methodResult, new Comparator<BluetoothLeDevice>() {
|
||||
|
||||
@Override
|
||||
public int compare(final BluetoothLeDevice arg0, final BluetoothLeDevice arg1) {
|
||||
return arg0.getAddress().compareToIgnoreCase(arg1.getAddress());
|
||||
}
|
||||
});
|
||||
|
||||
return methodResult;
|
||||
}
|
||||
|
||||
private String getListAsCsv() {
|
||||
final List<BluetoothLeDevice> list = getDeviceList();
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(CsvWriterHelper.addStuff("mac"));
|
||||
sb.append(CsvWriterHelper.addStuff("name"));
|
||||
sb.append(CsvWriterHelper.addStuff("firstTimestamp"));
|
||||
sb.append(CsvWriterHelper.addStuff("firstRssi"));
|
||||
sb.append(CsvWriterHelper.addStuff("currentTimestamp"));
|
||||
sb.append(CsvWriterHelper.addStuff("currentRssi"));
|
||||
sb.append(CsvWriterHelper.addStuff("adRecord"));
|
||||
sb.append(CsvWriterHelper.addStuff("iBeacon"));
|
||||
sb.append(CsvWriterHelper.addStuff("uuid"));
|
||||
sb.append(CsvWriterHelper.addStuff("major"));
|
||||
sb.append(CsvWriterHelper.addStuff("minor"));
|
||||
sb.append(CsvWriterHelper.addStuff("txPower"));
|
||||
sb.append(CsvWriterHelper.addStuff("distance"));
|
||||
sb.append(CsvWriterHelper.addStuff("accuracy"));
|
||||
sb.append('\n');
|
||||
|
||||
for (final BluetoothLeDevice device : list) {
|
||||
sb.append(CsvWriterHelper.addStuff(device.getAddress()));
|
||||
sb.append(CsvWriterHelper.addStuff(device.getName()));
|
||||
sb.append(CsvWriterHelper.addStuff(TimeFormatter.getIsoDateTime(device.getFirstTimestamp())));
|
||||
sb.append(CsvWriterHelper.addStuff(device.getFirstRssi()));
|
||||
sb.append(CsvWriterHelper.addStuff(TimeFormatter.getIsoDateTime(device.getTimestamp())));
|
||||
sb.append(CsvWriterHelper.addStuff(device.getRssi()));
|
||||
sb.append(CsvWriterHelper.addStuff(ByteUtils.byteArrayToHexString(device.getScanRecord())));
|
||||
final boolean isIBeacon = BeaconUtils.getBeaconType(device) == BeaconType.IBEACON;
|
||||
final String uuid;
|
||||
final String minor;
|
||||
final String major;
|
||||
final String txPower;
|
||||
final String distance;
|
||||
final String accuracy;
|
||||
|
||||
if (isIBeacon) {
|
||||
final IBeaconDevice beacon = new IBeaconDevice(device);
|
||||
uuid = String.valueOf(beacon.getUUID());
|
||||
minor = String.valueOf(beacon.getMinor());
|
||||
major = String.valueOf(beacon.getMajor());
|
||||
txPower = String.valueOf(beacon.getCalibratedTxPower());
|
||||
distance = beacon.getDistanceDescriptor().toString().toLowerCase(Locale.US);
|
||||
accuracy = String.valueOf(beacon.getAccuracy());
|
||||
} else {
|
||||
uuid = "";
|
||||
minor = "";
|
||||
major = "";
|
||||
txPower = "";
|
||||
distance = "";
|
||||
accuracy = "";
|
||||
}
|
||||
|
||||
sb.append(CsvWriterHelper.addStuff(isIBeacon));
|
||||
sb.append(CsvWriterHelper.addStuff(uuid));
|
||||
sb.append(CsvWriterHelper.addStuff(minor));
|
||||
sb.append(CsvWriterHelper.addStuff(major));
|
||||
sb.append(CsvWriterHelper.addStuff(txPower));
|
||||
sb.append(CsvWriterHelper.addStuff(distance));
|
||||
sb.append(CsvWriterHelper.addStuff(accuracy));
|
||||
|
||||
sb.append('\n');
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void shareDataAsEmail(final Context context) {
|
||||
final long timeInMillis = System.currentTimeMillis();
|
||||
|
||||
final String to = null;
|
||||
final String subject = "";
|
||||
|
||||
final String message = "";
|
||||
|
||||
final Intent i = new Intent(Intent.ACTION_SEND);
|
||||
i.setType("plain/text");
|
||||
try {
|
||||
final File outputDir = context.getCacheDir();
|
||||
final File outputFile = File.createTempFile("bluetooth_le_" + timeInMillis, ".csv", outputDir);
|
||||
outputFile.setReadable(true, false);
|
||||
generateFile(outputFile, getListAsCsv());
|
||||
i.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(outputFile));
|
||||
i.putExtra(Intent.EXTRA_EMAIL, new String[]{to});
|
||||
i.putExtra(Intent.EXTRA_SUBJECT, subject);
|
||||
i.putExtra(Intent.EXTRA_TEXT, message);
|
||||
context.startActivity(Intent.createChooser(i, "Email Subject"));
|
||||
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static FileWriter generateFile(final File file, final String contents) {
|
||||
FileWriter writer = null;
|
||||
try {
|
||||
writer = new FileWriter(file);
|
||||
writer.append(contents);
|
||||
writer.flush();
|
||||
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
writer.close();
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return writer;
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.wso2.carbon.iot.android.sense.bmonitor;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
|
||||
public class BluetoothLeScanner {
|
||||
private final Handler mHandler;
|
||||
private final BluetoothAdapter.LeScanCallback mLeScanCallback;
|
||||
private final BluetoothUtils mBluetoothUtils;
|
||||
private boolean mScanning;
|
||||
|
||||
public BluetoothLeScanner(final BluetoothAdapter.LeScanCallback leScanCallback, final BluetoothUtils bluetoothUtils) {
|
||||
mHandler = new Handler();
|
||||
mLeScanCallback = leScanCallback;
|
||||
mBluetoothUtils = bluetoothUtils;
|
||||
}
|
||||
|
||||
public boolean isScanning() {
|
||||
return mScanning;
|
||||
}
|
||||
|
||||
public void scanLeDevice(final int duration, final boolean enable) {
|
||||
if (enable) {
|
||||
if (mScanning) {
|
||||
return;
|
||||
}
|
||||
Log.d("TAG", "~ Starting Scan");
|
||||
// Stops scanning after a pre-defined scan period.
|
||||
if (duration > 0) {
|
||||
mHandler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Log.d("TAG", "~ Stopping Scan (timeout)");
|
||||
mScanning = false;
|
||||
mBluetoothUtils.getBluetoothAdapter().stopLeScan(mLeScanCallback);
|
||||
}
|
||||
}, duration);
|
||||
}
|
||||
mScanning = true;
|
||||
mBluetoothUtils.getBluetoothAdapter().startLeScan(mLeScanCallback);
|
||||
} else {
|
||||
Log.d("TAG", "~ Stopping Scan");
|
||||
mScanning = false;
|
||||
mBluetoothUtils.getBluetoothAdapter().stopLeScan(mLeScanCallback);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.wso2.carbon.iot.android.sense.bmonitor;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
|
||||
public final class BluetoothUtils {
|
||||
public final static int REQUEST_ENABLE_BT = 2001;
|
||||
private final Activity mActivity;
|
||||
private final BluetoothAdapter mBluetoothAdapter;
|
||||
|
||||
public BluetoothUtils(final Activity activity) {
|
||||
mActivity = activity;
|
||||
final BluetoothManager btManager = (BluetoothManager) mActivity.getSystemService(Context.BLUETOOTH_SERVICE);
|
||||
mBluetoothAdapter = btManager.getAdapter();
|
||||
}
|
||||
|
||||
public void askUserToEnableBluetoothIfNeeded() {
|
||||
if (isBluetoothLeSupported() && (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled())) {
|
||||
final Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
|
||||
mActivity.startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
|
||||
}
|
||||
}
|
||||
|
||||
public BluetoothAdapter getBluetoothAdapter() {
|
||||
return mBluetoothAdapter;
|
||||
}
|
||||
|
||||
public boolean isBluetoothLeSupported() {
|
||||
return mActivity.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE);
|
||||
}
|
||||
|
||||
public boolean isBluetoothOn() {
|
||||
if (mBluetoothAdapter == null) {
|
||||
return false;
|
||||
} else {
|
||||
return mBluetoothAdapter.isEnabled();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.wso2.carbon.iot.android.sense.bmonitor;
|
||||
|
||||
public class CsvWriterHelper {
|
||||
private static final String QUOTE = "\"";
|
||||
|
||||
public static String addStuff(final Integer text) {
|
||||
return QUOTE + text + QUOTE + ",";
|
||||
}
|
||||
|
||||
public static String addStuff(final Long text) {
|
||||
return QUOTE + text + QUOTE + ",";
|
||||
}
|
||||
|
||||
public static String addStuff(final boolean value) {
|
||||
return QUOTE + value + QUOTE + ",";
|
||||
}
|
||||
|
||||
public static String addStuff(String text) {
|
||||
if (text == null) {
|
||||
text = "<blank>";
|
||||
}
|
||||
text = text.replace(QUOTE, "'");
|
||||
|
||||
return QUOTE + text.trim() + QUOTE + ",";
|
||||
}
|
||||
}
|
@ -0,0 +1,154 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.wso2.carbon.iot.android.sense.bmonitor;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.support.v4.widget.SimpleCursorAdapter;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import agent.sense.android.iot.carbon.wso2.org.wso2_senseagent.R;
|
||||
import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice;
|
||||
import uk.co.alt236.bluetoothlelib.device.beacon.BeaconType;
|
||||
import uk.co.alt236.bluetoothlelib.device.beacon.BeaconUtils;
|
||||
import uk.co.alt236.bluetoothlelib.device.beacon.ibeacon.IBeaconDevice;
|
||||
import uk.co.alt236.easycursor.objectcursor.EasyObjectCursor;
|
||||
|
||||
public class LeDeviceListAdapter extends SimpleCursorAdapter {
|
||||
private final LayoutInflater mInflator;
|
||||
private final Activity mActivity;
|
||||
|
||||
public static final DecimalFormat DOUBLE_TWO_DIGIT_ACCURACY = new DecimalFormat("#.##");
|
||||
public static final String TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
public LeDeviceListAdapter(final Activity activity, final EasyObjectCursor<BluetoothLeDevice> cursor) {
|
||||
super(activity, R.layout.list_item_device, cursor, new String[0], new int[0], 0);
|
||||
mInflator = activity.getLayoutInflater();
|
||||
mActivity = activity;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public EasyObjectCursor<BluetoothLeDevice> getCursor() {
|
||||
return ((EasyObjectCursor<BluetoothLeDevice>) super.getCursor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BluetoothLeDevice getItem(final int i) {
|
||||
return getCursor().getItem(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(final int i) {
|
||||
return i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final int i, View view, final ViewGroup viewGroup) {
|
||||
final ViewHolder viewHolder;
|
||||
// General ListView optimization code.
|
||||
if (view == null) {
|
||||
view = mInflator.inflate(R.layout.list_item_device, null);
|
||||
viewHolder = new ViewHolder();
|
||||
viewHolder.deviceAddress = (TextView) view.findViewById(R.id.device_address);
|
||||
viewHolder.deviceName = (TextView) view.findViewById(R.id.device_name);
|
||||
viewHolder.deviceRssi = (TextView) view.findViewById(R.id.device_rssi);
|
||||
viewHolder.deviceIcon = (ImageView) view.findViewById(R.id.device_icon);
|
||||
viewHolder.deviceLastUpdated = (TextView) view.findViewById(R.id.device_last_update);
|
||||
viewHolder.ibeaconMajor = (TextView) view.findViewById(R.id.ibeacon_major);
|
||||
viewHolder.ibeaconMinor = (TextView) view.findViewById(R.id.ibeacon_minor);
|
||||
viewHolder.ibeaconDistance = (TextView) view.findViewById(R.id.ibeacon_distance);
|
||||
viewHolder.ibeaconUUID = (TextView) view.findViewById(R.id.ibeacon_uuid);
|
||||
viewHolder.ibeaconTxPower = (TextView) view.findViewById(R.id.ibeacon_tx_power);
|
||||
viewHolder.ibeaconSection = view.findViewById(R.id.ibeacon_section);
|
||||
viewHolder.ibeaconDistanceDescriptor = (TextView) view.findViewById(R.id.ibeacon_distance_descriptor);
|
||||
view.setTag(viewHolder);
|
||||
} else {
|
||||
viewHolder = (ViewHolder) view.getTag();
|
||||
}
|
||||
|
||||
final BluetoothLeDevice device = getCursor().getItem(i);
|
||||
final String deviceName = device.getName();
|
||||
|
||||
final double rssi = device.getRssi();
|
||||
|
||||
if (deviceName != null && deviceName.length() > 0) {
|
||||
viewHolder.deviceName.setText(deviceName + " (" + BeaconMonitoringActivity.itemMap.get(device.getAddress()) + ")");
|
||||
} else {
|
||||
viewHolder.deviceName.setText(R.string.unknown_device);
|
||||
}
|
||||
|
||||
|
||||
if (BeaconUtils.getBeaconType(device) == BeaconType.IBEACON) {
|
||||
final IBeaconDevice iBeacon = new IBeaconDevice(device);
|
||||
final String accuracy = DOUBLE_TWO_DIGIT_ACCURACY.format(iBeacon.getAccuracy());
|
||||
|
||||
viewHolder.deviceIcon.setImageResource(R.drawable.beacon);
|
||||
viewHolder.ibeaconSection.setVisibility(View.VISIBLE);
|
||||
viewHolder.ibeaconMajor.setText(String.valueOf(iBeacon.getMajor()));
|
||||
viewHolder.ibeaconMinor.setText(String.valueOf(iBeacon.getMinor()));
|
||||
viewHolder.ibeaconTxPower.setText(String.valueOf(iBeacon.getCalibratedTxPower()));
|
||||
viewHolder.ibeaconUUID.setText(iBeacon.getUUID());
|
||||
viewHolder.ibeaconDistance.setText(
|
||||
mActivity.getString(R.string.formatter_meters, accuracy));
|
||||
viewHolder.ibeaconDistanceDescriptor.setText(iBeacon.getDistanceDescriptor().toString());
|
||||
} else {
|
||||
if(device.getRssi() > BeaconMonitoringActivity.MINIMUM_DISTANCE){
|
||||
viewHolder.deviceIcon.setImageResource(R.drawable.beacon_red);
|
||||
}else{
|
||||
viewHolder.deviceIcon.setImageResource(R.drawable.beacon);
|
||||
}
|
||||
|
||||
viewHolder.ibeaconSection.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
|
||||
final String rssiString =
|
||||
mActivity.getString(R.string.formatter_db, String.valueOf(rssi));
|
||||
final String runningAverageRssiString =
|
||||
mActivity.getString(R.string.formatter_db, String.valueOf(device.getRunningAverageRssi()));
|
||||
|
||||
viewHolder.deviceLastUpdated.setText(
|
||||
android.text.format.DateFormat.format(
|
||||
TIME_FORMAT, new java.util.Date(device.getTimestamp())));
|
||||
viewHolder.deviceAddress.setText(device.getAddress());
|
||||
viewHolder.deviceRssi.setText(rssiString + " / " + runningAverageRssiString);
|
||||
return view;
|
||||
}
|
||||
|
||||
static class ViewHolder {
|
||||
TextView deviceName;
|
||||
TextView deviceAddress;
|
||||
TextView deviceRssi;
|
||||
TextView ibeaconUUID;
|
||||
TextView ibeaconMajor;
|
||||
TextView ibeaconMinor;
|
||||
TextView ibeaconTxPower;
|
||||
TextView ibeaconDistance;
|
||||
TextView ibeaconDistanceDescriptor;
|
||||
TextView deviceLastUpdated;
|
||||
View ibeaconSection;
|
||||
ImageView deviceIcon;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.wso2.carbon.iot.android.sense.bmonitor;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
public class TimeFormatter {
|
||||
private final static String ISO_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS zzz";
|
||||
private final static SimpleDateFormat ISO_FORMATTER = new UtcDateFormatter(ISO_FORMAT, Locale.US);
|
||||
|
||||
public static String getIsoDateTime(final Date date) {
|
||||
return ISO_FORMATTER.format(date);
|
||||
}
|
||||
|
||||
public static String getIsoDateTime(final long millis) {
|
||||
return getIsoDateTime(new Date(millis));
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/**
|
||||
* ****************************************************************************
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
|
||||
* <p/>
|
||||
* GenieConnect Ltd. ("COMPANY") CONFIDENTIAL
|
||||
* Unpublished Copyright (c) 2010-2013 GenieConnect Ltd., All Rights Reserved.
|
||||
* <p/>
|
||||
* NOTICE:
|
||||
* All information contained herein is, and remains the property of COMPANY.
|
||||
* The intellectual and technical concepts contained herein are proprietary to
|
||||
* COMPANY and may be covered by U.S. and Foreign Patents, patents in process, and
|
||||
* are protected by trade secret or copyright law. Dissemination of this
|
||||
* information or reproduction of this material is strictly forbidden unless prior
|
||||
* written permission is obtained from COMPANY. Access to the source code
|
||||
* contained herein is hereby forbidden to anyone except current COMPANY employees,
|
||||
* managers or contractors who have executed Confidentiality and Non-disclosure
|
||||
* agreements explicitly covering such access.
|
||||
* <p/>
|
||||
* The copyright notice above does not evidence any actual or intended publication
|
||||
* or disclosure of this source code, which includes information that is
|
||||
* confidential and/or proprietary, and is a trade secret, of COMPANY.
|
||||
* <p/>
|
||||
* ANY REPRODUCTION, MODIFICATION, DISTRIBUTION, PUBLIC PERFORMANCE, OR PUBLIC
|
||||
* DISPLAY OF OR THROUGH USE OF THIS SOURCE CODE WITHOUT THE EXPRESS WRITTEN
|
||||
* CONSENT OF COMPANY IS STRICTLY PROHIBITED, AND IN VIOLATION OF APPLICABLE LAWS
|
||||
* AND INTERNATIONAL TREATIES. THE RECEIPT OR POSSESSION OF THIS SOURCE CODE
|
||||
* AND/OR RELATED INFORMATION DOES NOT CONVEY OR IMPLY ANY RIGHTS TO REPRODUCE,
|
||||
* DISCLOSE OR DISTRIBUTE ITS CONTENTS, OR TO MANUFACTURE, USE, OR SELL ANYTHING
|
||||
* THAT IT MAY DESCRIBE, IN WHOLE OR IN PART.
|
||||
* ****************************************************************************
|
||||
*/
|
||||
package org.wso2.carbon.iot.android.sense.bmonitor;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
|
||||
import java.text.DateFormatSymbols;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
public class UtcDateFormatter extends java.text.SimpleDateFormat {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final String TIME_ZONE_STRING = "UTC";
|
||||
private static final TimeZone TIME_ZONE_UTC = TimeZone.getTimeZone(TIME_ZONE_STRING);
|
||||
|
||||
@SuppressLint("SimpleDateFormat")
|
||||
public UtcDateFormatter(final String template) {
|
||||
super(template);
|
||||
super.setTimeZone(TIME_ZONE_UTC);
|
||||
}
|
||||
|
||||
@SuppressLint("SimpleDateFormat")
|
||||
public UtcDateFormatter(final String template, final DateFormatSymbols symbols) {
|
||||
super(template, symbols);
|
||||
super.setTimeZone(TIME_ZONE_UTC);
|
||||
}
|
||||
|
||||
public UtcDateFormatter(final String template, final Locale locale) {
|
||||
super(template, locale);
|
||||
super.setTimeZone(TIME_ZONE_UTC);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function will throw an UnsupportedOperationException.
|
||||
* You are not be able to change the TimeZone of this object
|
||||
*
|
||||
* (non-Javadoc)
|
||||
* @see java.text.DateFormat#setTimeZone(java.util.TimeZone)
|
||||
*/
|
||||
@Override
|
||||
public void setTimeZone(final TimeZone timezone) {
|
||||
throw new UnsupportedOperationException("This SimpleDateFormat can only be in " + TIME_ZONE_STRING);
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 19 KiB |
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="false">
|
||||
<shape android:shape="oval">
|
||||
<solid android:color="#fa09ad"/>
|
||||
</shape>
|
||||
</item>
|
||||
<item android:state_pressed="true">
|
||||
<shape android:shape="oval">
|
||||
<solid android:color="#c20586"/>
|
||||
</shape>
|
||||
</item>
|
||||
</selector>
|
After Width: | Height: | Size: 30 KiB |
@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/listContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignParentTop="true"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ListView
|
||||
android:id="@android:id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/empty"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_vertical|center_horizontal"
|
||||
android:text="@string/no_data"/>
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
@ -0,0 +1,21 @@
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="5dip" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:gravity="center_horizontal"
|
||||
android:text="Scanning..." />
|
||||
|
||||
<ListView
|
||||
android:id="@+id/list"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:divider="@android:color/darker_gray"
|
||||
android:dividerHeight="1dip" />
|
||||
|
||||
</RelativeLayout>
|
@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<Button
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:background="@drawable/round_button"
|
||||
android:gravity="center"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginStart="20dp"/>
|
||||
|
||||
|
||||
<Button
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:background="@drawable/round_button"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginStart="20dp"
|
||||
android:gravity="center" />
|
||||
|
||||
<Button
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:background="@drawable/round_button"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginStart="20dp"
|
||||
android:gravity="center" />
|
||||
|
||||
<Button
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:background="@drawable/round_button"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginStart="20dp"
|
||||
android:gravity="center" />
|
||||
|
||||
</LinearLayout>
|
@ -0,0 +1,203 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2013 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="top"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/device_icon"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:paddingRight="5dp"
|
||||
android:paddingTop="5dp"
|
||||
android:src="@drawable/beacon"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/device_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="24sp"/>
|
||||
|
||||
<GridLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:columnCount="2">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingRight="5dp"
|
||||
android:text="@string/label_mac"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/device_address"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="12sp"
|
||||
android:typeface="monospace"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingRight="5dp"
|
||||
android:text="@string/label_updated"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/device_last_update"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingRight="5dp"
|
||||
android:textSize="12sp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingRight="5dp"
|
||||
android:text="@string/label_rssi"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/device_rssi"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingRight="5dp"
|
||||
android:textSize="12sp"/>
|
||||
</GridLayout>
|
||||
|
||||
<GridLayout
|
||||
android:id="@+id/ibeacon_section"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:columnCount="4">
|
||||
|
||||
<!-- ROW 1 -->
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingRight="5dp"
|
||||
android:text="@string/label_uuid"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/ibeacon_uuid"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_columnSpan="3"
|
||||
android:paddingRight="5dp"
|
||||
android:textSize="12sp"/>
|
||||
|
||||
<!-- ROW 2 -->
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingRight="5dp"
|
||||
android:text="@string/label_major"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/ibeacon_major"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingRight="5dp"
|
||||
android:textSize="12sp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="5dp"
|
||||
android:paddingRight="5dp"
|
||||
android:text="@string/label_minor"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/ibeacon_minor"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingRight="5dp"
|
||||
android:textSize="12sp"/>
|
||||
|
||||
<!-- ROW 3 -->
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingRight="5dp"
|
||||
android:text="@string/label_tx_power"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/ibeacon_tx_power"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingRight="5dp"
|
||||
android:textSize="12sp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="5dp"
|
||||
android:paddingRight="5dp"
|
||||
android:text="@string/label_distance"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/ibeacon_distance"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingRight="5dp"
|
||||
android:textSize="12sp"/>
|
||||
|
||||
<!-- ROW 4 -->
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingRight="5dp"
|
||||
android:text="@string/label_decriptor"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/ibeacon_distance_descriptor"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_columnSpan="3"
|
||||
android:paddingRight="5dp"
|
||||
android:textSize="12sp"/>
|
||||
</GridLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
@ -0,0 +1,80 @@
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@android:color/white"
|
||||
android:paddingBottom="10dip"
|
||||
android:paddingTop="10dip" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/BEACON_uuid"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:gravity="left|top" >
|
||||
</TextView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/BEACON_major"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_below="@+id/BEACON_uuid"
|
||||
android:layout_marginTop="5dp"
|
||||
android:gravity="left|top" >
|
||||
</TextView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/BEACON_minor"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/BEACON_uuid"
|
||||
android:layout_marginLeft="10dip"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_toRightOf="@+id/BEACON_major"
|
||||
android:gravity="left|top" >
|
||||
</TextView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/BEACON_proximity"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_below="@+id/BEACON_major"
|
||||
android:layout_marginTop="5dp"
|
||||
android:gravity="left|top" >
|
||||
</TextView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/BEACON_rssi"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/BEACON_major"
|
||||
android:layout_marginLeft="10dip"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_toRightOf="@+id/BEACON_proximity"
|
||||
android:gravity="left|top" >
|
||||
</TextView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/BEACON_txpower"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/BEACON_major"
|
||||
android:layout_marginLeft="10dip"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_toRightOf="@+id/BEACON_rssi"
|
||||
android:gravity="left|top" >
|
||||
</TextView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/BEACON_range"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/BEACON_proximity"
|
||||
android:layout_marginLeft="10dip"
|
||||
android:layout_marginTop="5dp"
|
||||
android:gravity="left|top" >
|
||||
</TextView>
|
||||
|
||||
</RelativeLayout>
|
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<WebView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/webView1"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
/>
|
Loading…
Reference in new issue