initial version
This commit is contained in:
commit
a0d3e184f9
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/workspace.xml
|
||||
/.idea/libraries
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
.externalNativeBuild
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
BIN
android_antlib_4-14-0/android_antlib_4-14-0.jar
Normal file
BIN
android_antlib_4-14-0/android_antlib_4-14-0.jar
Normal file
Binary file not shown.
2
android_antlib_4-14-0/build.gradle
Normal file
2
android_antlib_4-14-0/build.gradle
Normal file
|
@ -0,0 +1,2 @@
|
|||
configurations.maybeCreate("default")
|
||||
artifacts.add("default", file('android_antlib_4-14-0.jar'))
|
1
app/.gitignore
vendored
Normal file
1
app/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/build
|
32
app/build.gradle
Normal file
32
app/build.gradle
Normal file
|
@ -0,0 +1,32 @@
|
|||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 24
|
||||
buildToolsVersion "25.0.0"
|
||||
defaultConfig {
|
||||
applicationId "xyz.hoyer.iconsole"
|
||||
minSdkVersion 15
|
||||
targetSdkVersion 24
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile fileTree(include: ['*.jar'], dir: 'libs')
|
||||
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
|
||||
exclude group: 'com.android.support', module: 'support-annotations'
|
||||
})
|
||||
compile 'com.android.support:appcompat-v7:24.2.1'
|
||||
compile 'com.android.support:support-v4:24.2.1'
|
||||
testCompile 'junit:junit:4.12'
|
||||
compile 'com.android.support.constraint:constraint-layout:1.0.2'
|
||||
provided project(':android_antlib_4-14-0')
|
||||
}
|
25
app/proguard-rules.pro
vendored
Normal file
25
app/proguard-rules.pro
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in /home/harald/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
|
25
app/src/main/AndroidManifest.xml
Normal file
25
app/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="xyz.hoyer.iconsole">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
<activity
|
||||
android:name=".ChannelList"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/FullscreenTheme">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<service android:name=".ChannelService"></service>
|
||||
</application>
|
||||
|
||||
</manifest>
|
40
app/src/main/java/com/dsi/ant/channel/PredefinedNetwork.java
Normal file
40
app/src/main/java/com/dsi/ant/channel/PredefinedNetwork.java
Normal file
|
@ -0,0 +1,40 @@
|
|||
package com.dsi.ant.channel;
|
||||
|
||||
/**
|
||||
* Created by harald on 24.04.17.
|
||||
*/
|
||||
|
||||
public enum PredefinedNetwork {
|
||||
INVALID(-1),
|
||||
PUBLIC(0),
|
||||
ANT_PLUS1(1), //
|
||||
ANT_FS(2);
|
||||
|
||||
private final int mRawValue;
|
||||
private static final PredefinedNetwork[] sValues = values();
|
||||
|
||||
private PredefinedNetwork(int rawValue) {
|
||||
this.mRawValue = rawValue;
|
||||
}
|
||||
|
||||
int getRawValue() {
|
||||
return this.mRawValue;
|
||||
}
|
||||
|
||||
private boolean equals(int rawValue) {
|
||||
return rawValue == this.mRawValue;
|
||||
}
|
||||
|
||||
static PredefinedNetwork create(int rawValue) {
|
||||
PredefinedNetwork code = INVALID;
|
||||
|
||||
for(int i = 0; i < sValues.length; ++i) {
|
||||
if(sValues[i].equals(rawValue)) {
|
||||
code = sValues[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
}
|
296
app/src/main/java/xyz/hoyer/iconsole/ChannelController.java
Normal file
296
app/src/main/java/xyz/hoyer/iconsole/ChannelController.java
Normal file
|
@ -0,0 +1,296 @@
|
|||
/*
|
||||
* Copyright 2012 Dynastream Innovations Inc.
|
||||
*
|
||||
* 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 xyz.hoyer.iconsole;
|
||||
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import com.dsi.ant.channel.AntChannel;
|
||||
import com.dsi.ant.channel.AntCommandFailedException;
|
||||
import com.dsi.ant.channel.IAntChannelEventHandler;
|
||||
import com.dsi.ant.message.ChannelId;
|
||||
import com.dsi.ant.message.ChannelType;
|
||||
import com.dsi.ant.message.fromant.AcknowledgedDataMessage;
|
||||
import com.dsi.ant.message.fromant.BroadcastDataMessage;
|
||||
import com.dsi.ant.message.fromant.ChannelEventMessage;
|
||||
import com.dsi.ant.message.fromant.MessageFromAntType;
|
||||
import com.dsi.ant.message.ipc.AntMessageParcel;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class ChannelController
|
||||
{
|
||||
// The device type and transmission type to be part of the channel ID message
|
||||
private static final int CHANNEL_PROOF_DEVICE_TYPE = 0x08;
|
||||
private static final int CHANNEL_PROOF_TRANSMISSION_TYPE = 1;
|
||||
|
||||
// The period and frequency values the channel will be configured to
|
||||
private static final int CHANNEL_PROOF_PERIOD = 32768; // 1 Hz
|
||||
private static final int CHANNEL_PROOF_FREQUENCY = 77;
|
||||
|
||||
private static final String TAG = ChannelController.class.getSimpleName();
|
||||
|
||||
private static Random randGen = new Random();
|
||||
|
||||
private AntChannel mAntChannel;
|
||||
private ChannelBroadcastListener mChannelBroadcastListener;
|
||||
|
||||
private ChannelEventCallback mChannelEventCallback = new ChannelEventCallback();
|
||||
|
||||
private ChannelInfo mChannelInfo;
|
||||
|
||||
private boolean mIsOpen;
|
||||
|
||||
static public abstract class ChannelBroadcastListener
|
||||
{
|
||||
public abstract void onBroadcastChanged(ChannelInfo newInfo);
|
||||
}
|
||||
|
||||
public ChannelController(AntChannel antChannel, boolean isMaster, int deviceId,
|
||||
ChannelBroadcastListener broadcastListener)
|
||||
{
|
||||
mAntChannel = antChannel;
|
||||
mChannelInfo = new ChannelInfo(deviceId, isMaster, randGen.nextInt(256));
|
||||
mChannelBroadcastListener = broadcastListener;
|
||||
|
||||
openChannel();
|
||||
}
|
||||
|
||||
|
||||
boolean openChannel()
|
||||
{
|
||||
if(null != mAntChannel)
|
||||
{
|
||||
if(mIsOpen)
|
||||
{
|
||||
Log.w(TAG, "Channel was already open");
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Although this reference code sets ChannelType to either a transmitting master or a receiving slave,
|
||||
* the standard for ANT is that channels communication is bidirectional. The use of single-direction
|
||||
* communication in this app is for ease of understanding as reference code. For more information and
|
||||
* any additional features on ANT channel communication, refer to the ANT Protocol Doc found at:
|
||||
* http://www.thisisant.com/resources/ant-message-protocol-and-usage/
|
||||
*/
|
||||
ChannelType channelType = (mChannelInfo.isMaster ?
|
||||
ChannelType.BIDIRECTIONAL_MASTER : ChannelType.BIDIRECTIONAL_SLAVE);
|
||||
|
||||
// Channel ID message contains device number, type and transmission type. In
|
||||
// order for master (TX) channels and slave (RX) channels to connect, they
|
||||
// must have the same channel ID, or wildcard (0) is used.
|
||||
ChannelId channelId = new ChannelId(mChannelInfo.deviceNumber,
|
||||
CHANNEL_PROOF_DEVICE_TYPE, CHANNEL_PROOF_TRANSMISSION_TYPE);
|
||||
|
||||
try
|
||||
{
|
||||
// Setting the channel event handler so that we can receive messages from ANT
|
||||
mAntChannel.setChannelEventHandler(mChannelEventCallback);
|
||||
|
||||
// Performs channel assignment by assigning the type to the channel. Additional
|
||||
// features (such as, background scanning and frequency agility) can be enabled
|
||||
// by passing an ExtendedAssignment object to assign(ChannelType, ExtendedAssignment).
|
||||
mAntChannel.assign(channelType);
|
||||
|
||||
/*
|
||||
* Configures the channel ID, messaging period and rf frequency after assigning,
|
||||
* then opening the channel.
|
||||
*
|
||||
* For any additional ANT features such as proximity search or background scanning, refer to
|
||||
* the ANT Protocol Doc found at:
|
||||
* http://www.thisisant.com/resources/ant-message-protocol-and-usage/
|
||||
*/
|
||||
mAntChannel.setChannelId(channelId);
|
||||
mAntChannel.setPeriod(CHANNEL_PROOF_PERIOD);
|
||||
mAntChannel.setRfFrequency(CHANNEL_PROOF_FREQUENCY);
|
||||
mAntChannel.open();
|
||||
mIsOpen = true;
|
||||
|
||||
Log.d(TAG, "Opened channel with device number: " + mChannelInfo.deviceNumber);
|
||||
} catch (RemoteException e) {
|
||||
channelError(e);
|
||||
} catch (AntCommandFailedException e) {
|
||||
// This will release, and therefore unassign if required
|
||||
channelError("Open failed", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.w(TAG, "No channel available");
|
||||
}
|
||||
|
||||
return mIsOpen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the Channel Event Handler Interface so that messages can be
|
||||
* received and channel death events can be handled.
|
||||
*/
|
||||
public class ChannelEventCallback implements IAntChannelEventHandler
|
||||
{
|
||||
private void updateData(byte[] data) {
|
||||
mChannelInfo.broadcastData = data;
|
||||
|
||||
mChannelBroadcastListener.onBroadcastChanged(mChannelInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChannelDeath()
|
||||
{
|
||||
// Display channel death message when channel dies
|
||||
displayChannelError("Channel Death");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceiveMessage(MessageFromAntType messageType, AntMessageParcel antParcel) {
|
||||
Log.d(TAG, "Rx: "+ antParcel);
|
||||
|
||||
// Switching on message type to handle different types of messages
|
||||
switch(messageType)
|
||||
{
|
||||
// If data message, construct from parcel and update channel data
|
||||
case BROADCAST_DATA:
|
||||
// Rx Data
|
||||
updateData(new BroadcastDataMessage(antParcel).getPayload());
|
||||
break;
|
||||
case ACKNOWLEDGED_DATA:
|
||||
// Rx Data
|
||||
updateData(new AcknowledgedDataMessage(antParcel).getPayload());
|
||||
break;
|
||||
case CHANNEL_EVENT:
|
||||
// Constructing channel event message from parcel
|
||||
ChannelEventMessage eventMessage = new ChannelEventMessage(antParcel);
|
||||
|
||||
// Switching on event code to handle the different types of channel events
|
||||
switch(eventMessage.getEventCode())
|
||||
{
|
||||
case TX:
|
||||
// Use old info as this is what remote device has just received
|
||||
mChannelBroadcastListener.onBroadcastChanged(mChannelInfo);
|
||||
|
||||
mChannelInfo.broadcastData[0]++;
|
||||
|
||||
if(mIsOpen)
|
||||
{
|
||||
try {
|
||||
// Setting the data to be broadcast on the next channel period
|
||||
mAntChannel.setBroadcastData(mChannelInfo.broadcastData);
|
||||
} catch (RemoteException e) {
|
||||
channelError(e);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case RX_SEARCH_TIMEOUT:
|
||||
// TODO May want to keep searching
|
||||
displayChannelError("No Device Found");
|
||||
break;
|
||||
case CHANNEL_CLOSED:
|
||||
case CHANNEL_COLLISION:
|
||||
case RX_FAIL:
|
||||
case RX_FAIL_GO_TO_SEARCH:
|
||||
case TRANSFER_RX_FAILED:
|
||||
case TRANSFER_TX_COMPLETED:
|
||||
case TRANSFER_TX_FAILED:
|
||||
case TRANSFER_TX_START:
|
||||
case UNKNOWN:
|
||||
// TODO More complex communication will need to handle these events
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ANT_VERSION:
|
||||
case BURST_TRANSFER_DATA:
|
||||
case CAPABILITIES:
|
||||
case CHANNEL_ID:
|
||||
case CHANNEL_RESPONSE:
|
||||
case CHANNEL_STATUS:
|
||||
case SERIAL_NUMBER:
|
||||
case OTHER:
|
||||
// TODO More complex communication will need to handle these message types
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ChannelInfo getCurrentInfo()
|
||||
{
|
||||
return mChannelInfo;
|
||||
}
|
||||
|
||||
void displayChannelError(String displayText)
|
||||
{
|
||||
mChannelInfo.die(displayText);
|
||||
mChannelBroadcastListener.onBroadcastChanged(mChannelInfo);
|
||||
}
|
||||
|
||||
void channelError(RemoteException e) {
|
||||
String logString = "Remote service communication failed.";
|
||||
|
||||
Log.e(TAG, logString);
|
||||
|
||||
displayChannelError(logString);
|
||||
}
|
||||
|
||||
void channelError(String error, AntCommandFailedException e) {
|
||||
StringBuilder logString;
|
||||
|
||||
if(e.getResponseMessage() != null) {
|
||||
String initiatingMessageId = "0x"+ Integer.toHexString(
|
||||
e.getResponseMessage().getInitiatingMessageId());
|
||||
String rawResponseCode = "0x"+ Integer.toHexString(
|
||||
e.getResponseMessage().getRawResponseCode());
|
||||
|
||||
logString = new StringBuilder(error)
|
||||
.append(". Command ")
|
||||
.append(initiatingMessageId)
|
||||
.append(" failed with code ")
|
||||
.append(rawResponseCode);
|
||||
} else {
|
||||
String attemptedMessageId = "0x"+ Integer.toHexString(
|
||||
e.getAttemptedMessageType().getMessageId());
|
||||
String failureReason = e.getFailureReason().toString();
|
||||
|
||||
logString = new StringBuilder(error)
|
||||
.append(". Command ")
|
||||
.append(attemptedMessageId)
|
||||
.append(" failed with reason ")
|
||||
.append(failureReason);
|
||||
}
|
||||
|
||||
Log.e(TAG, logString.toString());
|
||||
|
||||
mAntChannel.release();
|
||||
|
||||
displayChannelError("ANT Command Failed");
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
// TODO kill all our resources
|
||||
if (null != mAntChannel)
|
||||
{
|
||||
mIsOpen = false;
|
||||
|
||||
// Releasing the channel to make it available for others.
|
||||
// After releasing, the AntChannel instance cannot be reused.
|
||||
mAntChannel.release();
|
||||
mAntChannel = null;
|
||||
}
|
||||
|
||||
displayChannelError("Channel Closed");
|
||||
}
|
||||
}
|
54
app/src/main/java/xyz/hoyer/iconsole/ChannelInfo.java
Normal file
54
app/src/main/java/xyz/hoyer/iconsole/ChannelInfo.java
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright 2012 Dynastream Innovations Inc.
|
||||
*
|
||||
* 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 xyz.hoyer.iconsole;
|
||||
|
||||
import com.dsi.ant.message.fromant.DataMessage;
|
||||
|
||||
public class ChannelInfo
|
||||
{
|
||||
public final int deviceNumber;
|
||||
|
||||
/** Master / Slave */
|
||||
public final boolean isMaster;
|
||||
|
||||
public byte[] broadcastData = new byte[DataMessage.LENGTH_STANDARD_PAYLOAD];
|
||||
|
||||
public boolean error;
|
||||
private String mErrorMessage;
|
||||
|
||||
public ChannelInfo(int deviceNumber, boolean isMaster, int initialBroadcastValue)
|
||||
{
|
||||
this.deviceNumber = deviceNumber;
|
||||
this.isMaster = isMaster;
|
||||
|
||||
// Not actually concerned with this value, so can cast to byte and lose data without issues
|
||||
broadcastData[0] = (byte)initialBroadcastValue;
|
||||
|
||||
error = false;
|
||||
mErrorMessage = null;
|
||||
}
|
||||
|
||||
public void die(String errorMessage)
|
||||
{
|
||||
error = true;
|
||||
mErrorMessage = errorMessage;
|
||||
}
|
||||
|
||||
public String getErrorString()
|
||||
{
|
||||
return mErrorMessage;
|
||||
}
|
||||
}
|
387
app/src/main/java/xyz/hoyer/iconsole/ChannelList.java
Normal file
387
app/src/main/java/xyz/hoyer/iconsole/ChannelList.java
Normal file
|
@ -0,0 +1,387 @@
|
|||
/*
|
||||
* Copyright 2012 Dynastream Innovations Inc.
|
||||
*
|
||||
* 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 xyz.hoyer.iconsole;
|
||||
|
||||
import com.dsi.ant.channel.ChannelNotAvailableException;
|
||||
import xyz.hoyer.iconsole.ChannelService.ChannelChangedListener;
|
||||
import xyz.hoyer.iconsole.ChannelService.ChannelServiceComm;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.ListView;
|
||||
import android.widget.Toast;
|
||||
import android.widget.ToggleButton;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ChannelList extends Activity {
|
||||
private static final String TAG = ChannelList.class.getSimpleName();
|
||||
|
||||
private final String PREF_TX_BUTTON_CHECKED_KEY = "ChannelList.TX_BUTTON_CHECKED";
|
||||
private boolean mCreateChannelAsMaster;
|
||||
|
||||
private ChannelServiceComm mChannelService;
|
||||
|
||||
private ArrayList<String> mChannelDisplayList = new ArrayList<String>();
|
||||
private ArrayAdapter<String> mChannelListAdapter;
|
||||
private SparseArray<Integer> mIdChannelListIndexMap = new SparseArray<Integer>();
|
||||
|
||||
private boolean mChannelServiceBound = false;
|
||||
|
||||
private void initButtons()
|
||||
{
|
||||
Log.v(TAG, "initButtons...");
|
||||
|
||||
//Register Master/Slave Toggle handler
|
||||
ToggleButton toggleButton_MasterSlave = (ToggleButton)findViewById(R.id.toggleButton_MasterSlave);
|
||||
toggleButton_MasterSlave.setEnabled(mChannelServiceBound);
|
||||
toggleButton_MasterSlave.setChecked(mCreateChannelAsMaster);
|
||||
toggleButton_MasterSlave.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
|
||||
{
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton arg0, boolean enabled)
|
||||
{
|
||||
mCreateChannelAsMaster = enabled;
|
||||
}
|
||||
});
|
||||
|
||||
//Register Add Channel Button handler
|
||||
Button button_addChannel = (Button)findViewById(R.id.button_AddChannel);
|
||||
button_addChannel.setEnabled(mChannelServiceBound);
|
||||
button_addChannel.setOnClickListener(new OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
addNewChannel(mCreateChannelAsMaster);
|
||||
}
|
||||
});
|
||||
|
||||
//Register Clear Channels Button handler
|
||||
Button button_clearChannels = (Button)findViewById(R.id.button_ClearChannels);
|
||||
button_clearChannels.setEnabled(mChannelServiceBound);
|
||||
button_clearChannels.setOnClickListener(new OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
clearAllChannels();
|
||||
}
|
||||
});
|
||||
|
||||
Log.v(TAG, "...initButtons");
|
||||
}
|
||||
|
||||
private void initPrefs()
|
||||
{
|
||||
Log.v(TAG, "initPrefs...");
|
||||
|
||||
// Retrieves the app's current state of channel transmission mode
|
||||
// from preferences to handle app resuming.
|
||||
SharedPreferences preferences = getPreferences(MODE_PRIVATE);
|
||||
|
||||
mCreateChannelAsMaster = preferences.getBoolean(PREF_TX_BUTTON_CHECKED_KEY, true);
|
||||
|
||||
Log.v(TAG, "...initPrefs");
|
||||
}
|
||||
|
||||
private void savePrefs()
|
||||
{
|
||||
Log.v(TAG, "savePrefs...");
|
||||
|
||||
// Saves the app's current state of channel transmission mode to preferences
|
||||
SharedPreferences preferences = getPreferences(MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
|
||||
editor.putBoolean(PREF_TX_BUTTON_CHECKED_KEY, mCreateChannelAsMaster);
|
||||
|
||||
editor.commit();
|
||||
|
||||
Log.v(TAG, "...savePrefs");
|
||||
}
|
||||
|
||||
private void doBindChannelService()
|
||||
{
|
||||
Log.v(TAG, "doBindChannelService...");
|
||||
|
||||
// Binds to ChannelService. ChannelService binds and manages connection between the
|
||||
// app and the ANT Radio Service
|
||||
Intent bindIntent = new Intent(this, ChannelService.class);
|
||||
startService(bindIntent);
|
||||
mChannelServiceBound = bindService(bindIntent, mChannelServiceConnection, Context.BIND_AUTO_CREATE);
|
||||
|
||||
if(!mChannelServiceBound) //If the bind returns false, run the unbind method to update the GUI
|
||||
doUnbindChannelService();
|
||||
|
||||
Log.i(TAG, " Channel Service binding = "+ mChannelServiceBound);
|
||||
|
||||
Log.v(TAG, "...doBindChannelService");
|
||||
}
|
||||
|
||||
private void doUnbindChannelService()
|
||||
{
|
||||
Log.v(TAG, "doUnbindChannelService...");
|
||||
|
||||
if(mChannelServiceBound)
|
||||
{
|
||||
unbindService(mChannelServiceConnection);
|
||||
|
||||
mChannelServiceBound = false;
|
||||
}
|
||||
|
||||
((Button)findViewById(R.id.button_ClearChannels)).setEnabled(false);
|
||||
((Button)findViewById(R.id.button_AddChannel)).setEnabled(false);
|
||||
((Button)findViewById(R.id.toggleButton_MasterSlave)).setEnabled(false);
|
||||
|
||||
Log.v(TAG, "...doUnbindChannelService");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
Log.v(TAG, "onCreate...");
|
||||
|
||||
mChannelServiceBound = false;
|
||||
|
||||
setContentView(R.layout.activity_fullscreen);
|
||||
|
||||
initPrefs();
|
||||
|
||||
mChannelListAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, android.R.id.text1, mChannelDisplayList);
|
||||
ListView listView_channelList = (ListView)findViewById(R.id.listView_channelList);
|
||||
listView_channelList.setAdapter(mChannelListAdapter);
|
||||
|
||||
if(!mChannelServiceBound) doBindChannelService();
|
||||
|
||||
initButtons();
|
||||
|
||||
Log.v(TAG, "...onCreate");
|
||||
}
|
||||
|
||||
public void onBack() {
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy()
|
||||
{
|
||||
Log.v(TAG, "onDestroy...");
|
||||
|
||||
doUnbindChannelService();
|
||||
|
||||
if(isFinishing())
|
||||
{
|
||||
stopService(new Intent(this, ChannelService.class));
|
||||
}
|
||||
|
||||
mChannelServiceConnection = null;
|
||||
|
||||
savePrefs();
|
||||
|
||||
Log.v(TAG, "...onDestroy");
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
private ServiceConnection mChannelServiceConnection = new ServiceConnection()
|
||||
{
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder serviceBinder)
|
||||
{
|
||||
Log.v(TAG, "mChannelServiceConnection.onServiceConnected...");
|
||||
|
||||
mChannelService = (ChannelServiceComm) serviceBinder;
|
||||
|
||||
// Sets a listener that handles channel events
|
||||
mChannelService.setOnChannelChangedListener(new ChannelChangedListener()
|
||||
{
|
||||
// Occurs when a channel has new info/data
|
||||
@Override
|
||||
public void onChannelChanged(final ChannelInfo newInfo)
|
||||
{
|
||||
Integer index = mIdChannelListIndexMap.get(newInfo.deviceNumber);
|
||||
|
||||
if(null != index && index.intValue() < mChannelDisplayList.size())
|
||||
{
|
||||
mChannelDisplayList.set(index.intValue(), getDisplayText(newInfo));
|
||||
runOnUiThread(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
mChannelListAdapter.notifyDataSetChanged();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Updates the UI to allow/disallow acquiring new channels
|
||||
@Override
|
||||
public void onAllowAddChannel(boolean addChannelAllowed) {
|
||||
// Enable Add Channel button and Master/Slave toggle if
|
||||
// adding channels is allowed
|
||||
((Button)findViewById(R.id.button_AddChannel)).setEnabled(addChannelAllowed);
|
||||
((Button)findViewById(R.id.toggleButton_MasterSlave)).setEnabled(addChannelAllowed);
|
||||
}
|
||||
});
|
||||
|
||||
// Initial check when connecting to ChannelService if adding channels is allowed
|
||||
boolean allowAcquireChannel = mChannelService.isAddChannelAllowed();
|
||||
((Button)findViewById(R.id.button_AddChannel)).setEnabled(allowAcquireChannel);
|
||||
((Button)findViewById(R.id.toggleButton_MasterSlave)).setEnabled(allowAcquireChannel);
|
||||
|
||||
refreshList();
|
||||
|
||||
Log.v(TAG, "...mChannelServiceConnection.onServiceConnected");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName arg0)
|
||||
{
|
||||
Log.v(TAG, "mChannelServiceConnection.onServiceDisconnected...");
|
||||
|
||||
// Clearing and disabling when disconnecting from ChannelService
|
||||
mChannelService = null;
|
||||
|
||||
((Button)findViewById(R.id.button_ClearChannels)).setEnabled(false);
|
||||
((Button)findViewById(R.id.button_AddChannel)).setEnabled(false);
|
||||
((Button)findViewById(R.id.toggleButton_MasterSlave)).setEnabled(false);
|
||||
|
||||
Log.v(TAG, "...mChannelServiceConnection.onServiceDisconnected");
|
||||
}
|
||||
};
|
||||
|
||||
// This method is called when 'Add Channel' button is clicked
|
||||
private void addNewChannel(final boolean isMaster)
|
||||
{
|
||||
Log.v(TAG, "addNewChannel...");
|
||||
|
||||
if(null != mChannelService)
|
||||
{
|
||||
ChannelInfo newChannelInfo;
|
||||
try
|
||||
{
|
||||
// Telling the ChannelService to add a new channel. This method
|
||||
// in ChannelService contains code required to acquire an ANT
|
||||
// channel from ANT Radio Service.
|
||||
newChannelInfo = mChannelService.addNewChannel(isMaster);
|
||||
} catch (ChannelNotAvailableException e)
|
||||
{
|
||||
// Occurs when a channel is not available. Printing out the
|
||||
// stack trace will show why no channels are available.
|
||||
Toast.makeText(this, "Channel Not Available", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
if(null != newChannelInfo)
|
||||
{
|
||||
// Adding new channel info to the list
|
||||
addChannelToList(newChannelInfo);
|
||||
mChannelListAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
Log.v(TAG, "...addNewChannel");
|
||||
}
|
||||
|
||||
private void refreshList()
|
||||
{
|
||||
Log.v(TAG, "refreshList...");
|
||||
|
||||
if(null != mChannelService)
|
||||
{
|
||||
ArrayList<ChannelInfo> chInfoList = mChannelService.getCurrentChannelInfoForAllChannels();
|
||||
|
||||
mChannelDisplayList.clear();
|
||||
for(ChannelInfo i: chInfoList)
|
||||
{
|
||||
addChannelToList(i);
|
||||
}
|
||||
mChannelListAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
Log.v(TAG, "...refreshList");
|
||||
}
|
||||
|
||||
private void addChannelToList(ChannelInfo channelInfo)
|
||||
{
|
||||
Log.v(TAG, "addChannelToList...");
|
||||
|
||||
mIdChannelListIndexMap.put(channelInfo.deviceNumber, mChannelDisplayList.size());
|
||||
mChannelDisplayList.add(getDisplayText(channelInfo));
|
||||
|
||||
Log.v(TAG, "...addChannelToList");
|
||||
}
|
||||
|
||||
|
||||
private static String getDisplayText(ChannelInfo channelInfo)
|
||||
{
|
||||
Log.v(TAG, "getDisplayText...");
|
||||
String displayText = null;
|
||||
|
||||
if(channelInfo.error)
|
||||
{
|
||||
displayText = String.format("#%-6d !:%s", channelInfo.deviceNumber, channelInfo.getErrorString());
|
||||
}
|
||||
else
|
||||
{
|
||||
if(channelInfo.isMaster)
|
||||
{
|
||||
displayText = String.format("#%-6d Tx:[%2d]", channelInfo.deviceNumber, channelInfo.broadcastData[0] & 0xFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
displayText = String.format("#%-6d Rx:[%2d]", channelInfo.deviceNumber, channelInfo.broadcastData[0] & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
Log.v(TAG, "...getDisplayText");
|
||||
|
||||
return displayText;
|
||||
}
|
||||
|
||||
|
||||
private void clearAllChannels()
|
||||
{
|
||||
Log.v(TAG, "clearAllChannels...");
|
||||
|
||||
if(null != mChannelService)
|
||||
{
|
||||
// Telling ChannelService to close all the channels
|
||||
mChannelService.clearAllChannels();
|
||||
|
||||
mChannelDisplayList.clear();
|
||||
mIdChannelListIndexMap.clear();
|
||||
mChannelListAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
Log.v(TAG, "...clearAllChannels");
|
||||
}
|
||||
}
|
379
app/src/main/java/xyz/hoyer/iconsole/ChannelService.java
Normal file
379
app/src/main/java/xyz/hoyer/iconsole/ChannelService.java
Normal file
|
@ -0,0 +1,379 @@
|
|||
/*
|
||||
* Copyright 2012 Dynastream Innovations Inc.
|
||||
*
|
||||
* 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 xyz.hoyer.iconsole;
|
||||
|
||||
import xyz.hoyer.iconsole.ChannelController.ChannelBroadcastListener;
|
||||
|
||||
import com.dsi.ant.AntService;
|
||||
import com.dsi.ant.channel.AntChannel;
|
||||
import com.dsi.ant.channel.AntChannelProvider;
|
||||
import com.dsi.ant.channel.ChannelNotAvailableException;
|
||||
import com.dsi.ant.channel.PredefinedNetwork;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ChannelService extends Service
|
||||
{
|
||||
private static final String TAG = "ChannelService";
|
||||
|
||||
private Object mCreateChannel_LOCK = new Object();
|
||||
|
||||
SparseArray<ChannelController> mChannelControllerList = new SparseArray<ChannelController>();
|
||||
|
||||
ChannelChangedListener mListener;
|
||||
|
||||
int channelDeviceIdCounter = 0;
|
||||
|
||||
private boolean mAntRadioServiceBound;
|
||||
private AntService mAntRadioService = null;
|
||||
private AntChannelProvider mAntChannelProvider = null;
|
||||
private boolean mAllowAddChannel = false;
|
||||
|
||||
private ServiceConnection mAntRadioServiceConnection = new ServiceConnection()
|
||||
{
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service)
|
||||
{
|
||||
// Must pass in the received IBinder object to correctly construct an AntService object
|
||||
mAntRadioService = new AntService(service);
|
||||
|
||||
try {
|
||||
// Getting a channel provider in order to acquire channels
|
||||
mAntChannelProvider = mAntRadioService.getChannelProvider();
|
||||
|
||||
// Initial check for number of channels available
|
||||
boolean mChannelAvailable = mAntChannelProvider.getNumChannelsAvailable() > 0;
|
||||
// Initial check for if legacy interface is in use. If the
|
||||
// legacy interface is in use, applications can free the ANT
|
||||
// radio by attempting to acquire a channel.
|
||||
boolean legacyInterfaceInUse = mAntChannelProvider.isLegacyInterfaceInUse();
|
||||
|
||||
// If there are channels OR legacy interface in use, allow adding channels
|
||||
if(mChannelAvailable || legacyInterfaceInUse) {
|
||||
mAllowAddChannel = true;
|
||||
}
|
||||
else {
|
||||
// If no channels available AND legacy interface is not in use, disallow adding channels
|
||||
mAllowAddChannel = false;
|
||||
}
|
||||
|
||||
if(mAllowAddChannel) {
|
||||
if(null != mListener) {
|
||||
// Send an event that indicates if adding channels is allowed
|
||||
mListener.onAllowAddChannel(mAllowAddChannel);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (RemoteException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name)
|
||||
{
|
||||
die("Binder Died");
|
||||
|
||||
mAntChannelProvider = null;
|
||||
mAntRadioService = null;
|
||||
|
||||
if(mAllowAddChannel) { mListener.onAllowAddChannel(false); }
|
||||
mAllowAddChannel = false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
public interface ChannelChangedListener
|
||||
{
|
||||
/**
|
||||
* Occurs when a Channel's Info has changed (i.e. a newly created
|
||||
* channel, channel has transmitted or received data, or if channel has
|
||||
* been closed.
|
||||
*
|
||||
* @param newInfo The channel's updated info
|
||||
*/
|
||||
void onChannelChanged(ChannelInfo newInfo);
|
||||
|
||||
/**
|
||||
* Occurs when there is adding a channel is being allowed or disallowed.
|
||||
*
|
||||
* @param addChannelAllowed True if adding channels is allowed. False, otherwise.
|
||||
*/
|
||||
void onAllowAddChannel(boolean addChannelAllowed);
|
||||
}
|
||||
|
||||
/**
|
||||
* The interface used to communicate with the ChannelService
|
||||
*/
|
||||
public class ChannelServiceComm extends Binder
|
||||
{
|
||||
/**
|
||||
* Sets the listener to be used for channel changed event callbacks.
|
||||
*
|
||||
* @param listener The listener that will receive events
|
||||
*/
|
||||
void setOnChannelChangedListener(ChannelChangedListener listener)
|
||||
{
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the current info for all channels currently added.
|
||||
*
|
||||
* @return A list that contains info for all the channels
|
||||
*/
|
||||
ArrayList<ChannelInfo> getCurrentChannelInfoForAllChannels()
|
||||
{
|
||||
ArrayList<ChannelInfo> retList = new ArrayList<ChannelInfo>();
|
||||
for(int i = 0; i < mChannelControllerList.size(); i++)
|
||||
{
|
||||
ChannelController channel = mChannelControllerList.valueAt(i);
|
||||
|
||||
retList.add(channel.getCurrentInfo());
|
||||
}
|
||||
|
||||
return retList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquires and adds a channel from ANT Radio Service
|
||||
*
|
||||
* @param isMaster True if channel is transmitting, False if channel is receiving
|
||||
* @return The info for the newly acquired and added channel
|
||||
* @throws ChannelNotAvailableException
|
||||
*/
|
||||
ChannelInfo addNewChannel(final boolean isMaster) throws ChannelNotAvailableException
|
||||
{
|
||||
return createNewChannel(isMaster);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes all channels currently added.
|
||||
*/
|
||||
void clearAllChannels() { closeAllChannels(); }
|
||||
|
||||
/**
|
||||
* Queries if adding a channel is allowed.
|
||||
* @return True if adding a channel is allowed. False, otherwise.
|
||||
*/
|
||||
boolean isAddChannelAllowed() { return mAllowAddChannel; }
|
||||
}
|
||||
|
||||
private void closeAllChannels()
|
||||
{
|
||||
synchronized (mChannelControllerList)
|
||||
{
|
||||
// Closing all channels in the list
|
||||
for(int i = 0; i < mChannelControllerList.size(); i++)
|
||||
{
|
||||
mChannelControllerList.valueAt(i).close();
|
||||
}
|
||||
mChannelControllerList.clear();
|
||||
}
|
||||
|
||||
// Reset the device id counter
|
||||
channelDeviceIdCounter = 0;
|
||||
}
|
||||
|
||||
AntChannel acquireChannel() throws ChannelNotAvailableException
|
||||
{
|
||||
AntChannel mAntChannel = null;
|
||||
if(null != mAntChannelProvider)
|
||||
{
|
||||
try
|
||||
{
|
||||
/*
|
||||
* If applications require a channel with specific capabilities
|
||||
* (event buffering, background scanning etc.), a Capabilities
|
||||
* object should be created and then the specific capabilities
|
||||
* required set to true. Applications can specify both required
|
||||
* and desired Capabilities with both being passed in
|
||||
* acquireChannel(context, PredefinedNetwork,
|
||||
* requiredCapabilities, desiredCapabilities).
|
||||
*/
|
||||
mAntChannel = mAntChannelProvider.acquireChannel(this, PredefinedNetwork.ANT_PLUS1);
|
||||
/*
|
||||
NetworkKey mNK = new NetworkKey(new byte[] { (byte)0xb9, (byte)0xa5, (byte)0x21, (byte)0xfb,
|
||||
(byte)0xbd, (byte)0x72, (byte)0xc3, (byte)0x45 });
|
||||
Log.v(TAG, mNK.toString());
|
||||
mAntChannel = mAntChannelProvider.acquireChannelOnPrivateNetwork(this, mNK);
|
||||
*/
|
||||
} catch (RemoteException e)
|
||||
{
|
||||
die("ACP Remote Ex");
|
||||
}
|
||||
}
|
||||
return mAntChannel;
|
||||
}
|
||||
|
||||
public ChannelInfo createNewChannel(final boolean isMaster) throws ChannelNotAvailableException
|
||||
{
|
||||
ChannelController channelController = null;
|
||||
|
||||
synchronized(mCreateChannel_LOCK)
|
||||
{
|
||||
// Acquiring a channel from ANT Radio Service
|
||||
AntChannel antChannel = acquireChannel();
|
||||
|
||||
if(null != antChannel)
|
||||
{
|
||||
|
||||
channelDeviceIdCounter += 1;
|
||||
|
||||
// Constructing a controller that will manage and control the channel
|
||||
channelController = new ChannelController(antChannel, isMaster, channelDeviceIdCounter,
|
||||
new ChannelBroadcastListener()
|
||||
{
|
||||
@Override
|
||||
public void onBroadcastChanged(ChannelInfo newInfo)
|
||||
{
|
||||
// Sending a channel changed event when message from ANT is received
|
||||
mListener.onChannelChanged(newInfo);
|
||||
}
|
||||
});
|
||||
|
||||
mChannelControllerList.put(channelDeviceIdCounter, channelController);
|
||||
}
|
||||
}
|
||||
|
||||
if(null == channelController) return null;
|
||||
|
||||
return channelController.getCurrentInfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent arg0)
|
||||
{
|
||||
return new ChannelServiceComm();
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives AntChannelProvider state changes being sent from ANT Radio Service
|
||||
*/
|
||||
private final BroadcastReceiver mChannelProviderStateChangedReceiver = new BroadcastReceiver()
|
||||
{
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent)
|
||||
{
|
||||
if(AntChannelProvider.ACTION_CHANNEL_PROVIDER_STATE_CHANGED.equals(intent.getAction())) {
|
||||
boolean update = false;
|
||||
// Retrieving the data contained in the intent
|
||||
int numChannels = intent.getIntExtra(AntChannelProvider.NUM_CHANNELS_AVAILABLE, 0);
|
||||
boolean legacyInterfaceInUse = intent.getBooleanExtra(AntChannelProvider.LEGACY_INTERFACE_IN_USE, false);
|
||||
|
||||
if(mAllowAddChannel) {
|
||||
// Was a acquire channel allowed
|
||||
// If no channels available AND legacy interface is not in use, disallow acquiring of channels
|
||||
if(0 == numChannels && !legacyInterfaceInUse) {
|
||||
mAllowAddChannel = false;
|
||||
update = true;
|
||||
}
|
||||
} else {
|
||||
// Acquire channels not allowed
|
||||
// If there are channels OR legacy interface in use, allow acquiring of channels
|
||||
if(numChannels > 0 || legacyInterfaceInUse) {
|
||||
mAllowAddChannel = true;
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(update && (null != mListener)) {
|
||||
// AllowAddChannel has been changed, sending event callback
|
||||
mListener.onAllowAddChannel(mAllowAddChannel);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private void doBindAntRadioService()
|
||||
{
|
||||
if(BuildConfig.DEBUG) Log.v(TAG, "doBindAntRadioService");
|
||||
|
||||
// Start listing for channel available intents
|
||||
registerReceiver(mChannelProviderStateChangedReceiver, new IntentFilter(AntChannelProvider.ACTION_CHANNEL_PROVIDER_STATE_CHANGED));
|
||||
|
||||
// Creating the intent and calling context.bindService() is handled by
|
||||
// the static bindService() method in AntService
|
||||
mAntRadioServiceBound = AntService.bindService(this, mAntRadioServiceConnection);
|
||||
}
|
||||
|
||||
private void doUnbindAntRadioService()
|
||||
{
|
||||
if(BuildConfig.DEBUG) Log.v(TAG, "doUnbindAntRadioService");
|
||||
|
||||
// Stop listing for channel available intents
|
||||
try{
|
||||
unregisterReceiver(mChannelProviderStateChangedReceiver);
|
||||
} catch (IllegalArgumentException exception) {
|
||||
if(BuildConfig.DEBUG) Log.d(TAG, "Attempting to unregister a never registered Channel Provider State Changed receiver.");
|
||||
}
|
||||
|
||||
if(mAntRadioServiceBound)
|
||||
{
|
||||
try
|
||||
{
|
||||
unbindService(mAntRadioServiceConnection);
|
||||
}
|
||||
catch(IllegalArgumentException e)
|
||||
{
|
||||
// Not bound, that's what we want anyway
|
||||
}
|
||||
|
||||
mAntRadioServiceBound = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate()
|
||||
{
|
||||
super.onCreate();
|
||||
|
||||
mAntRadioServiceBound = false;
|
||||
|
||||
doBindAntRadioService();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy()
|
||||
{
|
||||
closeAllChannels();
|
||||
|
||||
doUnbindAntRadioService();
|
||||
mAntChannelProvider = null;
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
static void die(String error)
|
||||
{
|
||||
Log.e(TAG, "DIE: "+ error);
|
||||
}
|
||||
|
||||
}
|
23
build.gradle
Normal file
23
build.gradle
Normal file
|
@ -0,0 +1,23 @@
|
|||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.3.1'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
17
gradle.properties
Normal file
17
gradle.properties
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Project-wide Gradle settings.
|
||||
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx1536m
|
||||
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
160
gradlew
vendored
Executable file
160
gradlew
vendored
Executable file
|
@ -0,0 +1,160 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn ( ) {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die ( ) {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
esac
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||
function splitJvmOpts() {
|
||||
JVM_OPTS=("$@")
|
||||
}
|
||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||
|
||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
90
gradlew.bat
vendored
Normal file
90
gradlew.bat
vendored
Normal file
|
@ -0,0 +1,90 @@
|
|||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windowz variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
goto execute
|
||||
|
||||
:4NT_args
|
||||
@rem Get arguments from the 4NT Shell from JP Software
|
||||
set CMD_LINE_ARGS=%$
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
1
settings.gradle
Normal file
1
settings.gradle
Normal file
|
@ -0,0 +1 @@
|
|||
include ':app', ':android_antlib_4-14-0'
|
Loading…
Reference in a new issue