Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
initial commit based on the work of sven ströher
- Loading branch information
Showing
205 changed files
with
19,432 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/build |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
apply plugin: 'com.android.application' | ||
|
||
android { | ||
compileSdkVersion 25 | ||
buildToolsVersion "25.0.3" | ||
defaultConfig { | ||
applicationId "stroeher.sven.bluetooth_le_scanner" | ||
minSdkVersion 21 | ||
targetSdkVersion 25 | ||
versionCode 1 | ||
versionName "1.0" | ||
testInstrumentationRunner "android.support.settings_workactivity.runner.AndroidJUnitRunner" | ||
} | ||
buildTypes { | ||
release { | ||
minifyEnabled false | ||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' | ||
} | ||
debug { | ||
debuggable true | ||
} | ||
} | ||
} | ||
|
||
dependencies { | ||
compile fileTree(dir: 'libs', include: '*.jar') | ||
compile 'com.github.scribejava:scribejava-apis:4.1.1' | ||
compile 'com.android.support:appcompat-v7:25.3.1' | ||
compile 'com.android.support.constraint:constraint-layout:1.0.2' | ||
compile 'com.android.support:design:25.3.1' | ||
compile 'com.android.support:support-v4:25.3.1' | ||
testCompile 'junit:junit:4.12' | ||
} |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# Add project specific ProGuard rules here. | ||
# By default, the flags in this file are appended to flags specified | ||
# in C:\Users\Sven\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt | ||
# You can edit the include path and order by changing the proguardFiles | ||
# directive in build.gradle. | ||
# | ||
# For more details, see | ||
# http://developer.android.com/guide/developing/tools/proguard.html | ||
|
||
# Add any project specific keep options here: | ||
|
||
# If your project uses WebView with JS, uncomment the following | ||
# and specify the fully qualified class name to the JavaScript interface | ||
# class: | ||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview { | ||
# public *; | ||
#} | ||
|
||
# Uncomment this to preserve the line number information for | ||
# debugging stack traces. | ||
#-keepattributes SourceFile,LineNumberTable | ||
|
||
# If you keep the line number information, uncomment this to | ||
# hide the original source file name. | ||
#-renamesourcefileattribute SourceFile |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||
package="stroeher.sven.bluetooth_le_scanner"> | ||
|
||
<uses-sdk android:maxSdkVersion="21"/> | ||
|
||
<uses-permission android:name="android.permission.BLUETOOTH"/> | ||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> | ||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> | ||
<uses-permission android:name="android.permission.INTERNET"/> | ||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> | ||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> | ||
|
||
<uses-feature | ||
android:name="android.hardware.bluetooth_le" | ||
android:required="false"/> | ||
<!-- Only needed for Android 5.0 (API level 21) or higher. --> | ||
<uses-feature | ||
android:name="android.hardware.location.network" | ||
android:required="true"/> | ||
<uses-feature | ||
android:name="android.hardware.location.gps" | ||
android:required="true"/> | ||
|
||
<application | ||
android:allowBackup="true" | ||
android:icon="@mipmap/ic_launcher" | ||
android:label="@string/app_name" | ||
android:roundIcon="@mipmap/ic_launcher_round" | ||
android:supportsRtl="true" | ||
android:theme="@style/AppTheme"> | ||
<activity | ||
android:name=".activities.MainActivity" | ||
android:screenOrientation="portrait"> | ||
<intent-filter> | ||
<action android:name="android.intent.action.MAIN"/> | ||
|
||
<category android:name="android.intent.category.LAUNCHER"/> | ||
</intent-filter> | ||
</activity> | ||
<activity | ||
android:name=".activities.WorkActivity" | ||
android:label="WorkActivity" | ||
android:parentActivityName=".activities.ScanActivity" | ||
android:screenOrientation="portrait"/> | ||
<activity | ||
android:name=".activities.ScanActivity" | ||
android:label="WorkActivity" | ||
android:parentActivityName=".activities.MainActivity" | ||
android:screenOrientation="portrait"/> | ||
</application> | ||
|
||
</manifest> |
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,239 @@ | ||
package com.fitbit.api; | ||
|
||
import com.fitbit.api.client.http.OAuth; | ||
import com.fitbit.api.common.model.timeseries.TimeSeriesResourceType; | ||
import com.fitbit.api.model.APICollectionType; | ||
import com.fitbit.api.model.APIFormat; | ||
import com.fitbit.api.model.APIVersion; | ||
import com.fitbit.api.model.ApiCollectionProperty; | ||
import com.fitbit.api.model.FitbitResourceOwner; | ||
import org.apache.commons.logging.Log; | ||
import org.apache.commons.logging.LogFactory; | ||
import org.joda.time.LocalDate; | ||
import org.joda.time.format.DateTimeFormat; | ||
import org.joda.time.format.DateTimeFormatter; | ||
|
||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.io.InputStreamReader; | ||
import java.io.Reader; | ||
import java.util.UUID; | ||
|
||
public class APIUtil { | ||
|
||
private static final Log log = LogFactory.getLog(APIUtil.class); | ||
|
||
public static final String SIGNATURE_HEADER_NAME = "X-Fitbit-Signature"; | ||
public static final String UNSPECIFIED_SUBSCRIPTION_ID = ""; | ||
|
||
protected static final int TYPICAL_URL_LENGTH = 70; | ||
protected static final String[] DATE_FORMATS = new String[] { "yyyy-MM-dd", "yyyy-MM" }; | ||
protected static final int STREAM_BUFFER_SIZE = 1024; | ||
|
||
|
||
public static String constructFullUrl(String baseUrl, APIVersion version, FitbitResourceOwner owner, APICollectionType collectionType, LocalDate date, APIFormat format) { | ||
return nullSafeConstructUrl(baseUrl, version, owner, collectionType, date, null, format); | ||
} | ||
|
||
public static String constructFullUrl(String baseUrl, APIVersion version, FitbitResourceOwner owner, APICollectionType collectionType, ApiCollectionProperty collectionProperty, APIFormat format) { | ||
return nullSafeConstructUrl(baseUrl, version, owner, collectionType, collectionProperty, format); | ||
} | ||
|
||
public static String constructFullSubscriptionUrl(String baseUrl, APIVersion version, FitbitResourceOwner owner, APICollectionType collectionType, APIFormat format) { | ||
return constructFullSubscriptionUrl(baseUrl, version, owner, collectionType, UNSPECIFIED_SUBSCRIPTION_ID, format); | ||
} | ||
|
||
public static String constructFullSubscriptionUrl(String baseUrl, APIVersion version, FitbitResourceOwner owner, APICollectionType collectionType, String subscriptionId, APIFormat format) { | ||
return nullSafeConstructUrl(baseUrl, version, owner, collectionType, null, subscriptionId, format); | ||
} | ||
|
||
public static String constructRelativeUrl(FitbitResourceOwner owner, APICollectionType collectionType, LocalDate date) { | ||
return nullSafeConstructRelativeUrl(owner, collectionType, date, null); | ||
} | ||
|
||
public static String contextualizeUrl(String baseUrl, APIVersion version, String relativeUrl, APIFormat format) { | ||
return nullSafeContextualizeUrl(baseUrl, version, relativeUrl, format); | ||
} | ||
|
||
/** | ||
* Parses the given date string into a valid {@link LocalDate} object, | ||
* suitable for passing into many API methods. | ||
* | ||
* @param date | ||
* @return | ||
* @throws IllegalArgumentException if the given date can not be parsed | ||
*/ | ||
public static LocalDate parseDate(String date) { | ||
if (null==date || date.length() < 1) { | ||
throw new IllegalArgumentException("Invalid empty input."); | ||
} | ||
|
||
LocalDate result = null; | ||
|
||
for (String format : DATE_FORMATS) { | ||
if (date.length()==format.length()) { | ||
try { | ||
long time = DateTimeFormat.forPattern(format).parseMillis(date); | ||
result = new LocalDate(time); | ||
break; | ||
} catch (Exception e) { | ||
if (log.isDebugEnabled()) { | ||
log.debug("Pattern '" + format + "' does not match date input '" + date + "': " + e); | ||
} | ||
} | ||
} | ||
} | ||
|
||
if (null==result) { | ||
throw new IllegalArgumentException("Invalid input date: '" + date + "'"); | ||
} | ||
|
||
return result; | ||
} | ||
|
||
|
||
// TEST API inputStreamToString | ||
public static String inputStreamToString(InputStream is) throws IOException { | ||
StringBuilder sb = new StringBuilder(); | ||
|
||
Reader reader = new InputStreamReader(is); | ||
|
||
char[] buffer = new char[STREAM_BUFFER_SIZE]; | ||
int count; | ||
while ((count = reader.read(buffer)) > 0) { | ||
sb.append(buffer, 0, count); | ||
} | ||
|
||
return sb.toString(); | ||
} | ||
|
||
|
||
public static String generateSignature(String data, String secret) { | ||
OAuth oauth = new OAuth(null, secret); | ||
return oauth.generateSignature(data); | ||
} | ||
|
||
|
||
/* ********************************************************************* */ | ||
|
||
protected static String nullSafeConstructUrl(String baseUrl, APIVersion version, FitbitResourceOwner owner, APICollectionType collectionType, LocalDate date, String subscriptionId, APIFormat format) { | ||
return | ||
nullSafeContextualizeUrl( | ||
baseUrl, | ||
version, | ||
nullSafeConstructRelativeUrl( | ||
owner, | ||
collectionType, | ||
date, | ||
subscriptionId | ||
), | ||
format | ||
); | ||
} | ||
|
||
protected static String nullSafeConstructUrl(String baseUrl, APIVersion version, FitbitResourceOwner owner, APICollectionType collectionType, ApiCollectionProperty collectionProperty, APIFormat format) { | ||
return | ||
nullSafeContextualizeUrl( | ||
baseUrl, | ||
version, | ||
nullSafeConstructRelativeUrl( | ||
owner, | ||
collectionType, | ||
collectionProperty | ||
), | ||
format | ||
); | ||
} | ||
|
||
private static String nullSafeConstructRelativeUrl(FitbitResourceOwner owner, APICollectionType collectionType, ApiCollectionProperty collectionProperty) { | ||
StringBuilder sb = new StringBuilder(TYPICAL_URL_LENGTH); | ||
|
||
if (null!=owner) { | ||
sb.append("/" + owner.getResourceOwnerType().name() + "/" + owner.getId()); | ||
} | ||
if (null!=collectionType) { | ||
sb.append("/" + collectionType.getUrlPath()); | ||
} | ||
if (null!=collectionProperty) { | ||
sb.append("/" + collectionProperty); | ||
} | ||
|
||
return sb.toString(); | ||
} | ||
|
||
|
||
protected static String nullSafeConstructRelativeUrl(FitbitResourceOwner owner, APICollectionType collectionType, LocalDate date, String subscriptionId) { | ||
StringBuilder sb = new StringBuilder(TYPICAL_URL_LENGTH); | ||
|
||
if (null!=owner) { | ||
sb.append("/" + owner.getResourceOwnerType().name() + "/" + owner.getId()); | ||
} | ||
if (null!=collectionType) { | ||
if( null!= subscriptionId ) { | ||
sb.append("/"+collectionType.getSubscriptionPath()); | ||
} else { | ||
sb.append("/" + collectionType.getUrlPath()); | ||
} | ||
} | ||
if (null!=date) { | ||
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd"); | ||
sb.append("/date/" + formatter.print(date)); | ||
} | ||
if (null!=subscriptionId) { | ||
sb.append("/apiSubscriptions"); | ||
if (! subscriptionId.equals(UNSPECIFIED_SUBSCRIPTION_ID)) { | ||
sb.append("/" + subscriptionId); | ||
} | ||
} | ||
|
||
return sb.toString(); | ||
} | ||
|
||
|
||
protected static String nullSafeContextualizeUrl(String baseUrl, APIVersion version, String relativeUrl, APIFormat format) { | ||
StringBuilder sb = new StringBuilder(TYPICAL_URL_LENGTH); | ||
|
||
if (null!=baseUrl) { | ||
sb.append(baseUrl); | ||
} | ||
if (null!=version) { | ||
sb.append("/" + version.getVersion()); | ||
} | ||
if (null!=relativeUrl) { | ||
sb.append(relativeUrl); | ||
} | ||
if (null!=format) { | ||
sb.append("." + format.toString().toLowerCase()); | ||
} | ||
|
||
return sb.toString(); | ||
} | ||
|
||
public static String constructTimeSeriesUrl(String baseUrl, APIVersion version, FitbitResourceOwner owner, TimeSeriesResourceType resourceType, | ||
String startDate, String endDateOrPeriod, APIFormat format) { | ||
return baseUrl + '/' + version.getVersion() | ||
+ '/' + owner.getResourceOwnerType().name() + '/' + owner.getId() | ||
+ resourceType.getResourcePath() | ||
+ "/date/" + startDate | ||
+ '/' + endDateOrPeriod | ||
+ '.' + format.toString().toLowerCase(); | ||
} | ||
|
||
public static String constructTimeSeriesUrl(String baseUrl, APIVersion version, FitbitResourceOwner owner, TimeSeriesResourceType resourceType, | ||
String startDate, String endDateOrPeriod, | ||
String startTime, String endTime, APIFormat format) { | ||
return baseUrl + '/' + version.getVersion() | ||
+ '/' + owner.getResourceOwnerType().name() + '/' + owner.getId() | ||
+ resourceType.getResourcePath() | ||
+ "/date/" + startDate | ||
+ '/' + endDateOrPeriod | ||
+ "/time/" + startTime | ||
+ '/' + endTime | ||
+ '.' + format.toString().toLowerCase(); | ||
} | ||
|
||
public static String capitalize(String s) { | ||
if (s == null || s.length() == 0) return s; | ||
return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase(); | ||
} | ||
} |
Oops, something went wrong.