Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
apply plugin: 'com.android.application'

android {
compileSdkVersion 25
buildToolsVersion "25.0.1"
compileSdkVersion rootProject.ext.compile_sdk_version
buildToolsVersion rootProject.ext.build_tools_version
defaultConfig {
applicationId "za.co.riggaroo.androidthings.distributedpiano"
minSdkVersion 24
targetSdkVersion 25
targetSdkVersion rootProject.ext.target_sdk_version
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
Expand All @@ -20,14 +20,14 @@ android {
}

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
implementation fileTree(dir: 'libs', include: ['*.jar'])
androidTestImplementation("com.android.support.test.espresso:espresso-core:$espresso_version", {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.1.0'
implementation "com.android.support:appcompat-v7:$support_version"

compile 'com.google.android.things.contrib:driver-pwmspeaker:0.1'
provided 'com.google.android.things:androidthings:0.1-devpreview'
compile 'com.google.android.gms:play-services-nearby:10.0.1'
testCompile 'junit:junit:4.12'
implementation 'com.google.android.things.contrib:driver-pwmspeaker:0.1'
compileOnly "com.google.android.things:androidthings:$things_version"
implementation "com.google.android.gms:play-services-nearby:$play_services_version"
testImplementation "junit:junit:$junit_version"
}
11 changes: 6 additions & 5 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="za.co.riggaroo.androidthings.distributedpiano">

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- Required for Nearby Connections -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

<application
android:allowBackup="true"
Expand All @@ -11,10 +16,6 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<meta-data
android:name="com.google.android.gms.nearby.connection.SERVICE_ID"
android:value="@string/service_id" />


<activity android:name=".PianoActivity">
<intent-filter>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
package za.co.riggaroo.androidthings.distributedpiano;

import android.app.Activity;
import android.net.ConnectivityManager;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;

import com.google.android.things.contrib.driver.pwmspeaker.Speaker;

import java.io.IOException;

import static android.Manifest.permission.ACCESS_COARSE_LOCATION;

public class PianoActivity extends Activity implements PianoContract.View {

private static final String TAG = "PianoActivity";
private final static int REQUEST_PERMISSION_REQ_CODE = 33;
private Speaker speaker;

private PianoContract.Presenter presenter;
Expand All @@ -21,10 +25,44 @@ public class PianoActivity extends Activity implements PianoContract.View {
protected void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

if (hasRequiredPermissions()) {
startComponents();
} else {
requestRequiredPermissions();
}
}

@Override
public void onRequestPermissionsResult(final int requestCode, final @NonNull String[] permissions, final @NonNull int[] grantResults) {
switch (requestCode) {
case REQUEST_PERMISSION_REQ_CODE: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// We have been granted the Manifest.permission.ACCESS_COARSE_LOCATION permission. Now we may proceed with advertising.
startComponents();
presenter.attachView(this);
} else {
Log.w(TAG, "Required permissions not granted");
}
break;
}
}
}

private boolean hasRequiredPermissions() {
return checkSelfPermission(ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED;
}

private void requestRequiredPermissions() {
if (shouldShowRequestPermissionRationale(ACCESS_COARSE_LOCATION)) {
Log.w(TAG, "Location permission is required for this application");
}
requestPermissions(new String[]{ACCESS_COARSE_LOCATION}, REQUEST_PERMISSION_REQ_CODE);
}

private void startComponents() {
try {
speaker = new Speaker(BoardDefaults.getPwmPin());
presenter = new PianoPresenter(this, (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE),
getString(R.string.service_id), getPackageName());
presenter = new PianoPresenter(this, getString(R.string.service_id));
} catch (IOException e) {
throw new IllegalArgumentException("Piezo can't be opened, lets end this here.");
}
Expand All @@ -34,15 +72,17 @@ protected void onCreate(@Nullable final Bundle savedInstanceState) {
public void onStart() {
super.onStart();
Log.d(TAG, "onStart");
presenter.attachView(this);
if (presenter != null)
presenter.attachView(this);

}

@Override
public void onStop() {
super.onStop();
Log.d(TAG, "onStop");
presenter.detachView();
if (presenter != null)
presenter.detachView();

}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package za.co.riggaroo.androidthings.distributedpiano;


import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
Expand All @@ -12,42 +9,91 @@
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.nearby.Nearby;
import com.google.android.gms.nearby.connection.AppIdentifier;
import com.google.android.gms.nearby.connection.AppMetadata;
import com.google.android.gms.nearby.connection.AdvertisingOptions;
import com.google.android.gms.nearby.connection.ConnectionInfo;
import com.google.android.gms.nearby.connection.ConnectionLifecycleCallback;
import com.google.android.gms.nearby.connection.ConnectionResolution;
import com.google.android.gms.nearby.connection.Connections;
import com.google.android.gms.nearby.connection.ConnectionsStatusCodes;
import com.google.android.gms.nearby.connection.Payload;
import com.google.android.gms.nearby.connection.PayloadCallback;
import com.google.android.gms.nearby.connection.PayloadTransferUpdate;
import com.google.android.gms.nearby.connection.Strategy;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

class PianoPresenter implements PianoContract.Presenter, GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, Connections.ConnectionRequestListener, Connections.MessageListener {
GoogleApiClient.OnConnectionFailedListener {

private static final String TAG = "PianoPresenter";
private final GoogleApiClient googleApiClient;
private static final String DEVICE_NAME = "DistributedPiano";
private final String serviceId;
private final String packageName;
private PianoContract.View view;
private ConnectivityManager connectivityManager;

PianoPresenter(Context context, ConnectivityManager connectivityManager, String serviceId,
String packageName) throws IOException {
private final ConnectionLifecycleCallback connectionLifecycleCallback = new ConnectionLifecycleCallback() {
@Override
public void onConnectionInitiated(String endpointId, ConnectionInfo connectionInfo) {
Log.d(TAG, "Connection initiated from " + endpointId + " " + connectionInfo.getEndpointName());
Nearby.Connections.acceptConnection(googleApiClient, endpointId, payloadCallback);
}

@Override
public void onConnectionResult(String endpointId, ConnectionResolution connectionResolution) {
Log.d(TAG, "onConnectionResult");
if (connectionResolution.getStatus().isSuccess()) {
Log.d(TAG, "Endpoint " + endpointId + " connected");
} else {
Log.w(TAG, "Endpoint " + endpointId + " already connected");
}
}

@Override
public void onDisconnected(String endpointId) {
Log.d(TAG, endpointId + " disconnected");
}
};

private final PayloadCallback payloadCallback = new PayloadCallback() {
@Override
public void onPayloadReceived(String endpointId, Payload payload) {
Log.d(TAG, "onPayloadReceived");
double frequency = toDouble(payload.asBytes());
if (frequency == -1) {
view.stopPlayingNote();
return;
}
view.playNote(frequency);
}

@Override
public void onPayloadTransferUpdate(String endpointId, PayloadTransferUpdate payloadTransferUpdate) {
switch (payloadTransferUpdate.getStatus()) {
case PayloadTransferUpdate.Status.IN_PROGRESS:
Log.d(TAG, "onPayloadTransferUpdate " + payloadTransferUpdate.getBytesTransferred() + " bytes transferred");
break;
case PayloadTransferUpdate.Status.SUCCESS:
Log.d(TAG, "onPayloadTransferUpdate completed");
break;
case PayloadTransferUpdate.Status.FAILURE:
Log.d(TAG, "onPayloadTransferUpdate failed");
break;
}
}
};

PianoPresenter(Context context, String serviceId) throws IOException {
googleApiClient = new GoogleApiClient.Builder(context).addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).addApi(Nearby.CONNECTIONS_API).build();
this.serviceId = serviceId;
this.connectivityManager = connectivityManager;
this.packageName = packageName;
}

@Override
public void onConnected(@Nullable final Bundle bundle) {
Log.d(TAG, "onConnected!");
startAdvertising();

}

@Override
Expand All @@ -60,25 +106,11 @@ public void onConnectionFailed(@NonNull final ConnectionResult connectionResult)
Log.d(TAG, "onConnectionFailed");
}

private boolean isConnectedToNetwork() {
NetworkInfo info = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
NetworkInfo info1 = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_ETHERNET);

return (info != null && info.isConnectedOrConnecting()) || (info1 != null && info1.isConnectedOrConnecting());
}


private void startAdvertising() {
Log.d(TAG, "startAdvertising");
if (!isConnectedToNetwork()) {
Log.d(TAG, "startAdvertising: not connected to WiFi network.");
return;
}

List<AppIdentifier> appIdentifierList = new ArrayList<>();
appIdentifierList.add(new AppIdentifier(packageName));
AppMetadata appMetadata = new AppMetadata(appIdentifierList);
Nearby.Connections.startAdvertising(googleApiClient, serviceId, appMetadata, 0L, this)
AdvertisingOptions advertisingOptions = new AdvertisingOptions(Strategy.P2P_CLUSTER);
Nearby.Connections
.startAdvertising(googleApiClient, DEVICE_NAME, serviceId, connectionLifecycleCallback, advertisingOptions)
.setResultCallback(new ResultCallback<Connections.StartAdvertisingResult>() {
@Override
public void onResult(@NonNull Connections.StartAdvertisingResult result) {
Expand All @@ -99,44 +131,10 @@ public void onResult(@NonNull Connections.StartAdvertisingResult result) {
});
}

@Override
public void onConnectionRequest(final String endpointId, String deviceId, String endpointName, byte[] payload) {
Log.d(TAG, "onConnectionRequest");

Nearby.Connections.acceptConnectionRequest(googleApiClient, endpointId, payload, this)
.setResultCallback(new ResultCallback<Status>() {
@Override
public void onResult(@NonNull Status status) {
if (status.isSuccess()) {
Log.d(TAG, "acceptConnectionRequest: SUCCESS");

} else {
Log.d(TAG, "acceptConnectionRequest: FAILURE");
}
}
});
}

@Override
public void onMessageReceived(final String s, final byte[] bytes, final boolean b) {
Log.d(TAG, "onMessageReceived");
double frequency = toDouble(bytes);
if (frequency == -1) {
view.stopPlayingNote();
return;
}
view.playNote(frequency);
}

private static double toDouble(byte[] bytes) {
return ByteBuffer.wrap(bytes).getDouble();
}

@Override
public void onDisconnected(final String s) {

}

@Override
public void detachView() {
this.view = null;
Expand Down
13 changes: 12 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
buildscript {
repositories {
jcenter()
maven { url 'https://maven.google.com' }
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.0-beta2'
classpath 'com.android.tools.build:gradle:3.0.0-alpha4'

// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
Expand All @@ -15,9 +16,19 @@ buildscript {
allprojects {
repositories {
jcenter()
maven { url 'https://maven.google.com' }
}
}

task clean(type: Delete) {
delete rootProject.buildDir
}

ext.compile_sdk_version = 26
ext.build_tools_version = "26.0.0"
ext.target_sdk_version = 26
ext.support_version = "26.0.0-beta2"
ext.play_services_version = "11.0.1"
ext.things_version = "0.4.1-devpreview"
ext.junit_version = "4.12"
ext.espresso_version = "2.2.2"
4 changes: 2 additions & 2 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#Sun Jan 22 17:32:18 SAST 2017
#Mon Jun 19 08:39:43 BST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-rc-1-all.zip
Loading