From 1fe91b728a31498a06161574745c49c5a3c0170d Mon Sep 17 00:00:00 2001 From: Giovanni Harting Date: Sun, 13 Sep 2015 17:00:00 +0200 Subject: [PATCH] implemented things to the point where simple set/get of color is possible added complete add stripe mechanic --- app/build.gradle | 31 +- app/src/main/AndroidManifest.xml | 15 +- .../com/idlegandalf/ledd/ColorActivity.java | 223 ++++++++- .../idlegandalf/ledd/ColorApplication.java | 109 +++-- .../ledd/callbacks/AddControllerCallback.java | 8 +- .../ledd/callbacks/AddStripeCallback.java | 26 + .../ledd/callbacks/BaseCallback.java | 28 ++ .../ledd/callbacks/DiscoverCallback.java | 28 ++ .../ledd/callbacks/RecieveColorCallback.java | 6 +- .../ledd/callbacks/StripesCallback.java | 30 ++ .../ledd/components/AnswerTask.java | 5 +- .../ledd/components/Controller.java | 15 +- .../com/idlegandalf/ledd/components/HSV.java | 6 +- .../components/{Host.java => LedDDaemon.java} | 23 +- .../{RGBStripe.java => LedDRequest.java} | 21 +- .../ledd/components/LedStripe.java | 58 +++ .../idlegandalf/ledd/components/Sendable.java | 25 +- .../ledd/components/StripeGroup.java | 14 +- .../ledd/fragments/AddControllerDialog.java | 383 +++++++++++++++ .../ledd/fragments/AddDaemonDialog.java | 329 +++++++++++++ .../ledd/fragments/AddStripeDialog.java | 457 ++++++++++++++++++ .../ledd/fragments/DrawerFragment.java | 50 -- .../idlegandalf/ledd/helper/LedDHelper.java | 317 ++++++++++-- .../ledd/services/ColorService.java | 44 +- app/src/main/res/layout/activity_color.xml | 27 +- app/src/main/res/layout/drawer_fragment.xml | 97 ---- .../res/layout/fragment_addcontroller.xml | 103 ++++ .../main/res/layout/fragment_adddaemon.xml | 100 ++++ .../main/res/layout/fragment_addstripe.xml | 275 +++++++++++ app/src/main/res/layout/host_row.xml | 26 +- app/src/main/res/layout/navigation_header.xml | 35 ++ .../main/res/layout/spinner_dropdown_item.xml | 28 ++ app/src/main/res/layout/spinner_item.xml | 29 ++ app/src/main/res/menu/navigation_drawer.xml | 35 ++ build.gradle | 20 +- 35 files changed, 2700 insertions(+), 326 deletions(-) create mode 100644 app/src/main/java/com/idlegandalf/ledd/callbacks/AddStripeCallback.java create mode 100644 app/src/main/java/com/idlegandalf/ledd/callbacks/BaseCallback.java create mode 100644 app/src/main/java/com/idlegandalf/ledd/callbacks/DiscoverCallback.java create mode 100644 app/src/main/java/com/idlegandalf/ledd/callbacks/StripesCallback.java rename app/src/main/java/com/idlegandalf/ledd/components/{Host.java => LedDDaemon.java} (73%) rename app/src/main/java/com/idlegandalf/ledd/components/{RGBStripe.java => LedDRequest.java} (75%) create mode 100644 app/src/main/java/com/idlegandalf/ledd/components/LedStripe.java create mode 100644 app/src/main/java/com/idlegandalf/ledd/fragments/AddControllerDialog.java create mode 100644 app/src/main/java/com/idlegandalf/ledd/fragments/AddDaemonDialog.java create mode 100644 app/src/main/java/com/idlegandalf/ledd/fragments/AddStripeDialog.java delete mode 100644 app/src/main/java/com/idlegandalf/ledd/fragments/DrawerFragment.java delete mode 100644 app/src/main/res/layout/drawer_fragment.xml create mode 100644 app/src/main/res/layout/fragment_addcontroller.xml create mode 100644 app/src/main/res/layout/fragment_adddaemon.xml create mode 100644 app/src/main/res/layout/fragment_addstripe.xml create mode 100644 app/src/main/res/layout/navigation_header.xml create mode 100644 app/src/main/res/layout/spinner_dropdown_item.xml create mode 100644 app/src/main/res/layout/spinner_item.xml create mode 100644 app/src/main/res/menu/navigation_drawer.xml diff --git a/app/build.gradle b/app/build.gradle index f38315c..b618601 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,3 +1,21 @@ +/* + * LEDD Project + * Copyright (C) 2015 LEDD Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + buildscript { repositories { mavenCentral() @@ -16,11 +34,11 @@ apply plugin: 'com.github.ben-manes.versions' android { compileSdkVersion 23 - buildToolsVersion '23.0.0' + buildToolsVersion '23.0.1' defaultConfig { applicationId "com.idlegandalf.ledd" - minSdkVersion 16 + minSdkVersion 17 targetSdkVersion 23 versionCode 1 versionName "1.0" @@ -35,13 +53,14 @@ android { dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') - compile 'com.android.support:appcompat-v7:23.0.0' - compile 'com.android.support:support-v4:23.0.0' + compile 'com.android.support:appcompat-v7:23.0.1' + compile 'com.android.support:support-v4:23.0.1' compile 'com.squareup.okhttp:okhttp:2.5.0' compile 'com.google.code.gson:gson:2.3.1' compile 'com.jakewharton:butterknife:7.0.1' compile 'com.koushikdutta.async:androidasync:2.1.6' - compile 'com.android.support:design:23.0.0' - compile 'com.rarepebble:colorpicker:1.3.0' + compile 'com.android.support:design:23.0.1' + compile 'com.larswerkman:HoloColorPicker:1.5' + compile 'com.google.guava:guava:19.0-rc1' provided 'org.projectlombok:lombok:1.16.6' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index cecd32c..d1ad057 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -21,23 +21,26 @@ package="com.idlegandalf.ledd" xmlns:android="http://schemas.android.com/apk/res/android"> - - - + + + - + + - + @@ -49,7 +52,7 @@ + android:value="com.idlegandalf.ledd.ColorActivity"/> diff --git a/app/src/main/java/com/idlegandalf/ledd/ColorActivity.java b/app/src/main/java/com/idlegandalf/ledd/ColorActivity.java index 70dadb6..6e4e85c 100644 --- a/app/src/main/java/com/idlegandalf/ledd/ColorActivity.java +++ b/app/src/main/java/com/idlegandalf/ledd/ColorActivity.java @@ -18,11 +18,17 @@ package com.idlegandalf.ledd; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.res.Configuration; +import android.graphics.Color; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.Bundle; +import android.support.design.widget.NavigationView; +import android.support.design.widget.Snackbar; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBarDrawerToggle; import android.support.v7.app.AppCompatActivity; @@ -31,27 +37,44 @@ import android.view.Gravity; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; +import android.view.SubMenu; import android.view.View; -import com.idlegandalf.ledd.components.RGBStripe; -import com.idlegandalf.ledd.components.StripeGroup; +import com.idlegandalf.ledd.callbacks.RecieveColorCallback; +import com.idlegandalf.ledd.callbacks.StripesCallback; +import com.idlegandalf.ledd.components.HSV; +import com.idlegandalf.ledd.components.LedDDaemon; +import com.idlegandalf.ledd.components.LedStripe; +import com.idlegandalf.ledd.fragments.AddStripeDialog; import com.idlegandalf.ledd.helper.LedDHelper; +import com.larswerkman.holocolorpicker.ColorPicker; +import com.larswerkman.holocolorpicker.SVBar; + +import org.json.JSONException; + +import java.io.IOException; +import java.util.List; import butterknife.Bind; import butterknife.ButterKnife; -import hugo.weaving.DebugLog; -public class ColorActivity extends AppCompatActivity { +public class ColorActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener { @Bind(R.id.drawer_layout) DrawerLayout mDrawerLayout; @Bind(R.id.toolbar) Toolbar toolbar; + @Bind(R.id.drawer) + NavigationView navigationView; + @Bind(R.id.picker) + ColorPicker colorPicker; + @Bind(R.id.svbar) + SVBar svBar; private ActionBarDrawerToggle mDrawerToggle; - private LedDHelper mAPI; - private RGBStripe mActiveStripe; - private StripeGroup mActiveGroup; - private boolean firstRun = false; + private refreshDaemonsListener daemonsListener; + private List ledStripes; + private LedStripe mCurrentStripe; + private LedDHelper mCurrentHelper; @Override protected void onCreate(Bundle savedInstanceState) { @@ -63,11 +86,27 @@ public class ColorActivity extends AppCompatActivity { ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); if (networkInfo == null || !networkInfo.isConnected()) { - // TODO: Display error + // TODO: Display error (snackbar) } + colorPicker.addSVBar(svBar); + colorPicker.setShowOldCenterColor(false); + + colorPicker.setOnColorChangedListener(new ColorPicker.OnColorChangedListener() { + @Override + public void onColorChanged(int i) { + if (mCurrentStripe != null && mCurrentHelper != null) { + float[] hsv = new float[3]; + Color.colorToHSV(i, hsv); + mCurrentStripe.setColor(new HSV(hsv[0], hsv[1], hsv[2])); + mCurrentHelper.setColor(mCurrentStripe); + } + } + }); + + navigationView.setNavigationItemSelectedListener(this); setSupportActionBar(toolbar); - toolbar.setTitle("LedD"); + toolbar.setTitle(R.string.app_name); mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.string.app_name, R.string.app_name) { @@ -90,12 +129,16 @@ public class ColorActivity extends AppCompatActivity { getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setHomeButtonEnabled(true); } + + daemonsListener = new refreshDaemonsListener(); + registerReceiver(daemonsListener, new IntentFilter(ColorApplication.INTENT_ACTION_REFRESH)); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.color, menu); + return true; } @@ -139,17 +182,173 @@ public class ColorActivity extends AppCompatActivity { return super.onKeyDown(keyCode, event); } - @DebugLog @Override protected void onPause() { super.onPause(); ColorApplication.getInstance().teardown(); + unregisterReceiver(daemonsListener); } - @DebugLog @Override protected void onDestroy() { super.onDestroy(); ColorApplication.getInstance().teardown(); } + + @Override + protected void onResume() { + super.onResume(); + ColorApplication.getInstance().onResume(); + registerReceiver(daemonsListener, new IntentFilter(ColorApplication.INTENT_ACTION_REFRESH)); + try { + refreshStripes(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Override + public boolean onNavigationItemSelected(MenuItem menuItem) { + int id = menuItem.getItemId(); + + switch (id) { + case R.id.nv_add_stripe: + new AddStripeDialog().show(getFragmentManager(), ""); + return true; + case R.id.nv_settings: + return true; + } + + for (LedStripe stripe : ledStripes) { + if (stripe.getName().equals(menuItem.getTitle())) { + mCurrentStripe = stripe; + try { + mCurrentHelper = ColorApplication.getInstance().getHelperForDaemon(stripe.getLedDDaemon()); + } catch (IOException e) { + e.printStackTrace(); + } + mDrawerLayout.closeDrawer(Gravity.LEFT); + toolbar.setTitle(stripe.getName()); + try { + mCurrentHelper.getColor(mCurrentStripe, new RecieveColorCallback() { + @Override + public void onColorRecieved(LedStripe stripe) { + final HSV cColor = stripe.getColor(); + + runOnUiThread(new Runnable() { + @Override + public void run() { + colorPicker.setColor(Color.HSVToColor(new float[]{(float) cColor.getHue(), (float) cColor.getSaturation(), + (float) cColor.getValue()})); + } + }); + } + + @Override + public void onRecievFailed(String msg) { + + } + + @Override + public void onConnectionFailed(String message) { + + } + }); + } catch (JSONException | IOException e) { + e.printStackTrace(); + } + return true; + } + } + + return false; + } + + public void refreshStripes() throws IOException { + reCreateNavigationView(); // need to recreate the navigationview since we can't remove a once added submenu + + final Menu nvMenu = navigationView.getMenu(); + final int stripeGroup = 42; + + int i = 1; + for (final LedDDaemon dDaemon : ColorApplication.getInstance().getDaemons()) { + + LedDHelper helper = ColorApplication.getInstance().getHelperForDaemon(dDaemon); + + if (helper != null) { + try { + final int finalI = i; + helper.getStripes(new StripesCallback() { + @Override + public void onSuccess(final List stripes) { + runOnUiThread(new Runnable() { + @Override + public void run() { + SubMenu nDaemonMenu = nvMenu.addSubMenu(Menu.NONE, Menu.NONE, finalI, dDaemon.toString()); + nDaemonMenu.setGroupCheckable(stripeGroup, true, true); + + ledStripes = stripes; + Snackbar.make(findViewById(android.R.id.content), "LED stripes reloaded", Snackbar.LENGTH_LONG).show(); + + for (LedStripe stripe : ledStripes) { + MenuItem sItem = nDaemonMenu.add(stripeGroup, View.generateViewId(), stripe.getId(), stripe.getName()); + sItem.setIcon(R.drawable.ic_wb_iridescent_black_48dp); + } + } + }); + } + + @Override + public void onGetFailed(String message) { + Snackbar.make(findViewById(android.R.id.content), "Coudn't get stripes from daemon: " + message, Snackbar.LENGTH_LONG) + .show(); + + } + + @Override + public void onConnectionFailed(String message) { + Snackbar.make(findViewById(android.R.id.content), "Coudn't connect to daemon: " + message, Snackbar.LENGTH_LONG).show(); + } + }); + } catch (JSONException | IOException e) { + e.printStackTrace(); + } + } + + i++; + } + } + + private void reCreateNavigationView() { + runOnUiThread(new Runnable() { + @Override + public void run() { + mDrawerLayout.removeView(navigationView); + navigationView = new NavigationView(ColorActivity.this); + DrawerLayout.LayoutParams params = new DrawerLayout.LayoutParams(DrawerLayout.LayoutParams.WRAP_CONTENT, DrawerLayout.LayoutParams + .MATCH_PARENT); + params.gravity = Gravity.START; + navigationView.setLayoutParams(params); + navigationView.inflateMenu(R.menu.navigation_drawer); + navigationView.inflateHeaderView(R.layout.navigation_header); + mDrawerLayout.addView(navigationView, params); + navigationView.setNavigationItemSelectedListener(ColorActivity.this); + mDrawerToggle.syncState(); + } + }); + } + + protected class refreshDaemonsListener extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(ColorApplication.INTENT_ACTION_REFRESH)) { + try { + refreshStripes(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } } diff --git a/app/src/main/java/com/idlegandalf/ledd/ColorApplication.java b/app/src/main/java/com/idlegandalf/ledd/ColorApplication.java index 881b8d3..49eeb58 100644 --- a/app/src/main/java/com/idlegandalf/ledd/ColorApplication.java +++ b/app/src/main/java/com/idlegandalf/ledd/ColorApplication.java @@ -19,22 +19,29 @@ package com.idlegandalf.ledd; import android.app.Application; +import android.content.Intent; import android.preference.PreferenceManager; +import android.util.Log; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; -import com.idlegandalf.ledd.components.Host; +import com.idlegandalf.ledd.callbacks.DiscoverCallback; +import com.idlegandalf.ledd.components.LedDDaemon; import com.idlegandalf.ledd.helper.LedDHelper; +import org.json.JSONException; + import java.io.IOException; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Set; -import hugo.weaving.DebugLog; - public class ColorApplication extends Application { + public static final String TAG = "LedD"; + public static final String INTENT_ACTION_REFRESH = "com.idlegandalf.ledd.action.refreshStripes"; private static ColorApplication singleton; - private HashMap ledDHelpers; + private HashMap ledDHelpers; public static ColorApplication getInstance() { return singleton; @@ -46,41 +53,87 @@ public class ColorApplication extends Application { singleton = this; ledDHelpers = new HashMap<>(); - - if (PreferenceManager.getDefaultSharedPreferences(this).contains("hosts")) { - Set hosts = new Gson().fromJson(PreferenceManager.getDefaultSharedPreferences(this).getString("hosts", ""), new - TypeToken>() { - }.getType()); - - for (Host host : hosts) { - try { - ledDHelpers.put(host, new LedDHelper(host, getApplicationContext())); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - System.out.println("len of hashmap: " + ledDHelpers.size()); + this.onResume(); } - public LedDHelper getHelperForHost(Host host) throws IOException { - System.out.println("host: " + host.toString()); - if (ledDHelpers.containsKey(host)) { - return ledDHelpers.get(host); + public LedDHelper getHelperForDaemon(final LedDDaemon ledDDaemon) throws IOException { + if (ledDHelpers.containsKey(ledDDaemon) && ledDHelpers.get(ledDDaemon) != null) { + return ledDHelpers.get(ledDDaemon); } else { - LedDHelper dHelper = new LedDHelper(host, getApplicationContext()); - ledDHelpers.put(host, dHelper); + final LedDHelper dHelper = new LedDHelper(ledDDaemon, getApplicationContext()); + try { + dHelper.discover(new DiscoverCallback() { + @Override + public void onConnectionFailed(String message) { + + } + + @Override + public void onDiscoverSuccessfully(String version) { + ledDHelpers.put(ledDDaemon, dHelper); + } + }); + } catch (JSONException e) { + e.printStackTrace(); + } + + return dHelper; } } - @DebugLog + public List getDaemons() { + ArrayList ledDDaemons = new ArrayList<>(); + ledDDaemons.addAll(ledDHelpers.keySet()); + + return ledDDaemons; + } + public void teardown() { for (LedDHelper dHelper : ledDHelpers.values()) { dHelper.teardown(); } - PreferenceManager.getDefaultSharedPreferences(this).edit().putString("hosts", new Gson().toJson(ledDHelpers.keySet())).commit(); + PreferenceManager.getDefaultSharedPreferences(this).edit().putString("daemons", new Gson().toJson(ledDHelpers.keySet())).commit(); + } + + public void onResume() { + if (PreferenceManager.getDefaultSharedPreferences(this).contains("daemons")) { + Set ledDDaemons = new Gson().fromJson(PreferenceManager.getDefaultSharedPreferences(this).getString("daemons", ""), new + TypeToken>() { + }.getType()); + + for (final LedDDaemon ledDDaemon : ledDDaemons) { + try { + final LedDHelper helper = new LedDHelper(ledDDaemon, getApplicationContext()); + + helper.discover(new DiscoverCallback() { + @Override + public void onDiscoverSuccessfully(String version) { + //ledDDaemon.setActive(true); + ledDHelpers.put(ledDDaemon, helper); + + Intent i = new Intent(INTENT_ACTION_REFRESH); + sendBroadcast(i); + } + + @Override + public void onConnectionFailed(String message) { + //ledDDaemon.setActive(false); + ledDHelpers.put(ledDDaemon, helper); + + Intent i = new Intent(INTENT_ACTION_REFRESH); + sendBroadcast(i); + } + }); + + + } catch (IOException | JSONException e) { + e.printStackTrace(); + } + } + } + + Log.i(ColorApplication.TAG, "Loaded " + ledDHelpers.size() + " Daemons from preferences"); } } diff --git a/app/src/main/java/com/idlegandalf/ledd/callbacks/AddControllerCallback.java b/app/src/main/java/com/idlegandalf/ledd/callbacks/AddControllerCallback.java index 0de9ed4..2f44e6d 100644 --- a/app/src/main/java/com/idlegandalf/ledd/callbacks/AddControllerCallback.java +++ b/app/src/main/java/com/idlegandalf/ledd/callbacks/AddControllerCallback.java @@ -18,13 +18,15 @@ package com.idlegandalf.ledd.callbacks; -public interface AddControllerCallback { +import com.idlegandalf.ledd.components.Controller; + +public interface AddControllerCallback extends BaseCallback { /** * Returns when a controller was added successfully * - * @param cid the new controller's id + * @param controller the new controller */ - void onControllerAdded(int cid); + void onControllerAdded(Controller controller); void onAddFailed(String msg, String detail); } diff --git a/app/src/main/java/com/idlegandalf/ledd/callbacks/AddStripeCallback.java b/app/src/main/java/com/idlegandalf/ledd/callbacks/AddStripeCallback.java new file mode 100644 index 0000000..e85df6e --- /dev/null +++ b/app/src/main/java/com/idlegandalf/ledd/callbacks/AddStripeCallback.java @@ -0,0 +1,26 @@ +/* + * LEDD Project + * Copyright (C) 2015 LEDD Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.idlegandalf.ledd.callbacks; + + +import com.idlegandalf.ledd.components.LedStripe; + +public interface AddStripeCallback extends BaseCallback { + void onAddSuccessfully(LedStripe stripe); +} diff --git a/app/src/main/java/com/idlegandalf/ledd/callbacks/BaseCallback.java b/app/src/main/java/com/idlegandalf/ledd/callbacks/BaseCallback.java new file mode 100644 index 0000000..c32a40d --- /dev/null +++ b/app/src/main/java/com/idlegandalf/ledd/callbacks/BaseCallback.java @@ -0,0 +1,28 @@ +/* + * LEDD Project + * Copyright (C) 2015 LEDD Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.idlegandalf.ledd.callbacks; + +public interface BaseCallback { + /** + * Returns when there is a connection problem + * + * @param message error description + */ + void onConnectionFailed(String message); +} diff --git a/app/src/main/java/com/idlegandalf/ledd/callbacks/DiscoverCallback.java b/app/src/main/java/com/idlegandalf/ledd/callbacks/DiscoverCallback.java new file mode 100644 index 0000000..a80ff98 --- /dev/null +++ b/app/src/main/java/com/idlegandalf/ledd/callbacks/DiscoverCallback.java @@ -0,0 +1,28 @@ +/* + * LEDD Project + * Copyright (C) 2015 LEDD Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.idlegandalf.ledd.callbacks; + +public interface DiscoverCallback extends BaseCallback { + /** + * Returns when discover has succeded + * + * @param version the ledd daemon version string + */ + void onDiscoverSuccessfully(String version); +} diff --git a/app/src/main/java/com/idlegandalf/ledd/callbacks/RecieveColorCallback.java b/app/src/main/java/com/idlegandalf/ledd/callbacks/RecieveColorCallback.java index ae3db5e..ef09596 100644 --- a/app/src/main/java/com/idlegandalf/ledd/callbacks/RecieveColorCallback.java +++ b/app/src/main/java/com/idlegandalf/ledd/callbacks/RecieveColorCallback.java @@ -18,10 +18,10 @@ package com.idlegandalf.ledd.callbacks; -import com.idlegandalf.ledd.components.HSV; +import com.idlegandalf.ledd.components.LedStripe; -public interface RecieveColorCallback { - void onColorRecieved(HSV color); +public interface RecieveColorCallback extends BaseCallback { + void onColorRecieved(LedStripe stripe); void onRecievFailed(String msg); } diff --git a/app/src/main/java/com/idlegandalf/ledd/callbacks/StripesCallback.java b/app/src/main/java/com/idlegandalf/ledd/callbacks/StripesCallback.java new file mode 100644 index 0000000..f9f247a --- /dev/null +++ b/app/src/main/java/com/idlegandalf/ledd/callbacks/StripesCallback.java @@ -0,0 +1,30 @@ +/* + * LEDD Project + * Copyright (C) 2015 LEDD Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.idlegandalf.ledd.callbacks; + + +import com.idlegandalf.ledd.components.LedStripe; + +import java.util.List; + +public interface StripesCallback extends BaseCallback { + void onSuccess(List stripes); + + void onGetFailed(String message); +} diff --git a/app/src/main/java/com/idlegandalf/ledd/components/AnswerTask.java b/app/src/main/java/com/idlegandalf/ledd/components/AnswerTask.java index 51e4835..8033071 100644 --- a/app/src/main/java/com/idlegandalf/ledd/components/AnswerTask.java +++ b/app/src/main/java/com/idlegandalf/ledd/components/AnswerTask.java @@ -21,8 +21,9 @@ package com.idlegandalf.ledd.components; import org.json.JSONObject; -public abstract class AnswerTask implements Runnable { +public abstract class AnswerTask { + public abstract void onConnectionFailed(String message); - public JSONObject response; + public abstract void onResponse(JSONObject response); } diff --git a/app/src/main/java/com/idlegandalf/ledd/components/Controller.java b/app/src/main/java/com/idlegandalf/ledd/components/Controller.java index ec6eeb6..ef8b5b1 100644 --- a/app/src/main/java/com/idlegandalf/ledd/components/Controller.java +++ b/app/src/main/java/com/idlegandalf/ledd/components/Controller.java @@ -18,8 +18,6 @@ package com.idlegandalf.ledd.components; -import java.util.ArrayList; - import lombok.Getter; import lombok.Setter; @@ -27,8 +25,13 @@ import lombok.Setter; @Getter @Setter public class Controller { - private int channels; - private String address; - private int i2c_device; - private ArrayList stripes; + int id; + int channels; + String address; + int i2c_device; + + @Override + public String toString() { + return String.format("%s@/dev/i2c-%d (%d)", address, i2c_device, channels); + } } diff --git a/app/src/main/java/com/idlegandalf/ledd/components/HSV.java b/app/src/main/java/com/idlegandalf/ledd/components/HSV.java index 42ab86b..fe828ca 100644 --- a/app/src/main/java/com/idlegandalf/ledd/components/HSV.java +++ b/app/src/main/java/com/idlegandalf/ledd/components/HSV.java @@ -24,9 +24,9 @@ import lombok.Setter; @Getter @Setter public class HSV { - private double hue; - private double saturation; - private double value; + double hue; + double saturation; + double value; public HSV(double h, double s, double v) { this.hue = h; diff --git a/app/src/main/java/com/idlegandalf/ledd/components/Host.java b/app/src/main/java/com/idlegandalf/ledd/components/LedDDaemon.java similarity index 73% rename from app/src/main/java/com/idlegandalf/ledd/components/Host.java rename to app/src/main/java/com/idlegandalf/ledd/components/LedDDaemon.java index cf5db68..c49ee6a 100644 --- a/app/src/main/java/com/idlegandalf/ledd/components/Host.java +++ b/app/src/main/java/com/idlegandalf/ledd/components/LedDDaemon.java @@ -19,23 +19,28 @@ package com.idlegandalf.ledd.components; +import java.util.ArrayList; +import java.util.List; + import lombok.Getter; import lombok.Setter; @Getter @Setter -public class Host { - private String address; - private int port; +public class LedDDaemon { + String address; + int port; + List controllers; + String version; - public Host(String address, int port) { + public LedDDaemon(String address, int port) { this.address = address; this.port = port; + this.controllers = new ArrayList<>(); } - public Host() { - this.address = null; - this.port = 0; + public LedDDaemon() { + this(null, 0); } @Override @@ -45,8 +50,8 @@ public class Host { @Override public boolean equals(Object o) { - if (o instanceof Host) { - if (address.equals(((Host) o).address) && port == ((Host) o).port) return true; + if (o instanceof LedDDaemon) { + if (address.equals(((LedDDaemon) o).address) && port == ((LedDDaemon) o).port) return true; } return false; } diff --git a/app/src/main/java/com/idlegandalf/ledd/components/RGBStripe.java b/app/src/main/java/com/idlegandalf/ledd/components/LedDRequest.java similarity index 75% rename from app/src/main/java/com/idlegandalf/ledd/components/RGBStripe.java rename to app/src/main/java/com/idlegandalf/ledd/components/LedDRequest.java index 1e97205..b8273e2 100644 --- a/app/src/main/java/com/idlegandalf/ledd/components/RGBStripe.java +++ b/app/src/main/java/com/idlegandalf/ledd/components/LedDRequest.java @@ -18,18 +18,17 @@ package com.idlegandalf.ledd.components; +import org.json.JSONObject; + import lombok.Getter; -import lombok.Setter; @Getter -@Setter -public class RGBStripe { - private int id; - private int channelRed; - private int channelGreen; - private int channelBlue; - private String nice_name; - private HSV color; - private double gammaCorrection; +public class LedDRequest { + JSONObject request; + AnswerTask task; -} \ No newline at end of file + public LedDRequest(JSONObject request, AnswerTask task) { + this.request = request; + this.task = task; + } +} diff --git a/app/src/main/java/com/idlegandalf/ledd/components/LedStripe.java b/app/src/main/java/com/idlegandalf/ledd/components/LedStripe.java new file mode 100644 index 0000000..3ca182f --- /dev/null +++ b/app/src/main/java/com/idlegandalf/ledd/components/LedStripe.java @@ -0,0 +1,58 @@ +/* + * LEDD Project + * Copyright (C) 2015 LEDD Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.idlegandalf.ledd.components; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class LedStripe { + int id; + int channelRed; + int channelGreen; + int channelBlue; + String name; + HSV color; + double gammaCorrection; + boolean RGB; + Controller controller; + LedDDaemon ledDDaemon; + + public LedStripe() { + this(-1, -1, -1, -1, ""); + } + + public LedStripe(int channelRed, int channelGreen, int channelBlue, String name) { + this(-1, channelRed, channelGreen, channelBlue, name, true); + } + + public LedStripe(int id, int channelRed, int channelGreen, int channelBlue, String name) { + this(id, channelRed, channelGreen, channelBlue, name, true); + } + + public LedStripe(int id, int channelRed, int channelGreen, int channelBlue, String name, boolean RGB) { + this.id = id; + this.channelRed = channelRed; + this.channelGreen = channelGreen; + this.channelBlue = channelBlue; + this.name = name; + this.RGB = RGB; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/idlegandalf/ledd/components/Sendable.java b/app/src/main/java/com/idlegandalf/ledd/components/Sendable.java index b1286ad..af380fd 100644 --- a/app/src/main/java/com/idlegandalf/ledd/components/Sendable.java +++ b/app/src/main/java/com/idlegandalf/ledd/components/Sendable.java @@ -27,16 +27,16 @@ import lombok.Getter; @Getter public class Sendable { - private Host recipient; - private JSONObject message; - private String ref; - private AnswerTask onAnswer; + LedDDaemon recipient; + JSONObject message; + String ref; + AnswerTask onAnswer; - public Sendable(JSONObject msg, AnswerTask task, Host host) throws JSONException { - this(msg, UUID.randomUUID().toString(), task, host); + public Sendable(JSONObject msg, AnswerTask task, LedDDaemon ledDDaemon) throws JSONException { + this(msg, UUID.randomUUID().toString(), task, ledDDaemon); } - public Sendable(JSONObject msg, String ref, AnswerTask task, Host recipient) throws JSONException { + public Sendable(JSONObject msg, String ref, AnswerTask task, LedDDaemon recipient) throws JSONException { this.message = msg; this.ref = ref; this.message.put("ref", ref); @@ -46,8 +46,15 @@ public class Sendable { public void onResponse(JSONObject object) { if (onAnswer != null) { - onAnswer.response = object; - onAnswer.run(); + onAnswer.onResponse(object); } } + + public void onNoResponse() { + onAnswer.onConnectionFailed("no_response"); + } + + public void onConnectionFailed(String message) { + onAnswer.onConnectionFailed(message); + } } diff --git a/app/src/main/java/com/idlegandalf/ledd/components/StripeGroup.java b/app/src/main/java/com/idlegandalf/ledd/components/StripeGroup.java index 2a1da0c..9df4a90 100644 --- a/app/src/main/java/com/idlegandalf/ledd/components/StripeGroup.java +++ b/app/src/main/java/com/idlegandalf/ledd/components/StripeGroup.java @@ -27,9 +27,9 @@ import java.io.IOException; import java.util.ArrayList; public class StripeGroup { - private String mNiceName; - private String mDescription; - private ArrayList mStripes; + String mNiceName; + String mDescription; + ArrayList mStripes; public String getNiceName() { return mNiceName; @@ -47,11 +47,11 @@ public class StripeGroup { this.mDescription = mDescription; } - public RGBStripe getStripeByPos(int pos) { + public LedStripe getStripeByPos(int pos) { return mStripes.get(pos); } - public RGBStripe getStripeById(int sid) { + public LedStripe getStripeById(int sid) { for (int i = 0; i < mStripes.size(); i++) { if (mStripes.get(i).getId() == sid) { return mStripes.get(i); @@ -66,12 +66,12 @@ public class StripeGroup { } } - public int addStripe(RGBStripe stripe) { + public int addStripe(LedStripe stripe) { mStripes.add(stripe); return mStripes.size() - 1; } - public void removeStripeByObject(RGBStripe stripe) { + public void removeStripeByObject(LedStripe stripe) { for (int i = 0; i < mStripes.size(); i++) { if (mStripes.get(i).getId() == stripe.getId()) { mStripes.remove(i); diff --git a/app/src/main/java/com/idlegandalf/ledd/fragments/AddControllerDialog.java b/app/src/main/java/com/idlegandalf/ledd/fragments/AddControllerDialog.java new file mode 100644 index 0000000..95842fd --- /dev/null +++ b/app/src/main/java/com/idlegandalf/ledd/fragments/AddControllerDialog.java @@ -0,0 +1,383 @@ +/* + * LEDD Project + * Copyright (C) 2015 LEDD Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.idlegandalf.ledd.fragments; + +import android.app.Dialog; +import android.app.DialogFragment; +import android.content.DialogInterface; +import android.os.Bundle; +import android.support.design.widget.Snackbar; +import android.support.design.widget.TextInputLayout; +import android.support.v7.app.AlertDialog; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; + +import com.google.gson.Gson; +import com.idlegandalf.ledd.ColorApplication; +import com.idlegandalf.ledd.R; +import com.idlegandalf.ledd.callbacks.AddControllerCallback; +import com.idlegandalf.ledd.components.Controller; +import com.idlegandalf.ledd.components.LedDDaemon; +import com.idlegandalf.ledd.helper.LedDHelper; + +import org.json.JSONException; + +import java.io.IOException; +import java.text.NumberFormat; +import java.text.ParsePosition; + +import butterknife.Bind; +import butterknife.ButterKnife; + +public class AddControllerDialog extends DialogFragment implements DialogInterface.OnShowListener { + + @Bind(R.id.input_i2c_layout) + TextInputLayout i2cLayout; + @Bind(R.id.input_i2c) + EditText i2cText; + @Bind(R.id.input_address_layout) + TextInputLayout addressLayout; + @Bind(R.id.input_address) + EditText addressText; + @Bind(R.id.input_channel_layout) + TextInputLayout channelLayout; + @Bind(R.id.input_channel) + EditText channelText; + LedDDaemon dDaemon; + + public Dialog onCreateDialog(Bundle savedInstanceState) { + View v = View.inflate(getActivity(), R.layout.fragment_addcontroller, null); + ButterKnife.bind(this, v); + + dDaemon = new Gson().fromJson(getArguments().getString("daemon"), LedDDaemon.class); + + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + builder.setView(v).setPositiveButton("Add", null).setNegativeButton("Cancel", null); + + AlertDialog dialog = builder.create(); + + dialog.setOnShowListener(this); + + return dialog; + } + + @Override + public void onShow(final DialogInterface dialog) { + + final AlertDialog alertDialog = (AlertDialog) dialog; + + addressText.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + addressLayout.setError(null); + } + }); + + channelText.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + channelLayout.setError(null); + } + }); + + i2cText.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + i2cLayout.setError(null); + } + }); + + alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + AddStripeDialog.instance.onResume(); + alertDialog.dismiss(); + } + }); + + alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (i2cText.getText().toString().isEmpty() || !isNumeric(i2cText.getText().toString())) { + i2cLayout.setError("No valid i2c device number"); + return; + } + + if (!addressText.getText().toString().contains("0x") || !addressText.getText().toString().split("x")[1].matches("-?[0-9a-fA-F]+")) { + addressLayout.setError("No valid hexdecimal address"); + return; + } + + if (channelText.getText().toString().isEmpty() || !isNumeric(channelText.getText().toString()) && Integer.parseInt(channelText + .getText().toString()) <= 0) { + channelLayout.setError("No valid channel amount"); + return; + } + + Controller c = new Controller(); + c.setAddress(addressText.getText().toString()); + c.setI2c_device(Integer.parseInt(i2cText.getText().toString())); + c.setChannels(Integer.parseInt(channelText.getText().toString())); + + LedDHelper helper = null; + try { + helper = ColorApplication.getInstance().getHelperForDaemon(dDaemon); + } catch (IOException e) { + e.printStackTrace(); + } + + if (helper != null) { + try { + helper.addController(c, new AddControllerCallback() { + @Override + public void onControllerAdded(final Controller controller) { + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + Snackbar.make(((ViewGroup) getActivity().getWindow().getDecorView().findViewById(android.R.id.content)) + .getChildAt(0), "Added Controller (" + controller.getId() + ")", Snackbar.LENGTH_LONG).show(); + } + }); + + dDaemon.getControllers().add(controller); + dismiss(); + } + + @Override + public void onAddFailed(final String msg, String detail) { + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + Snackbar.make(((ViewGroup) getActivity().getWindow().getDecorView().findViewById(android.R.id.content)) + .getChildAt(0), "Error: " + msg, Snackbar.LENGTH_LONG).show(); + } + }); + AddStripeDialog.instance.onResume(); + dismiss(); + } + + @Override + public void onConnectionFailed(final String message) { + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + Snackbar.make(((ViewGroup) getActivity().getWindow().getDecorView().findViewById(android.R.id.content)) + .getChildAt(0), "Coudn't connect to" + + " daemon at " + dDaemon + ": " + message, Snackbar.LENGTH_LONG).show(); + } + }); + AddStripeDialog.instance.onResume(); + dismiss(); + } + }); + } catch (JSONException | IOException e) { + e.printStackTrace(); + } + } + } + }); + } + + @Override + public void onShow(final DialogInterface dialog) { + + final AlertDialog alertDialog = (AlertDialog) dialog; + + addressText.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + addressLayout.setError(null); + } + }); + + channelText.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + channelLayout.setError(null); + } + }); + + i2cText.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + i2cLayout.setError(null); + } + }); + + alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + AddStripeDialog.instance.onResume(); + alertDialog.dismiss(); + } + }); + + alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (i2cText.getText().toString().isEmpty() || !isNumeric(i2cText.getText().toString())) { + i2cLayout.setError("No valid i2c device number"); + return; + } + + if (!addressText.getText().toString().contains("0x") || !addressText.getText().toString().split("x")[1].matches("-?[0-9a-fA-F]+")) { + addressLayout.setError("No valid hexdecimal address"); + return; + } + + if (channelText.getText().toString().isEmpty() || !isNumeric(channelText.getText().toString()) && Integer.parseInt(channelText + .getText().toString()) <= 0) { + channelLayout.setError("No valid channel amount"); + return; + } + + Controller c = new Controller(); + c.setAddress(addressText.getText().toString()); + c.setI2c_device(Integer.parseInt(i2cText.getText().toString())); + c.setChannels(Integer.parseInt(channelText.getText().toString())); + + LedDHelper helper = null; + try { + helper = ColorApplication.getInstance().getHelperForDaemon(dDaemon); + } catch (IOException e) { + e.printStackTrace(); + } + + if (helper != null) { + try { + helper.addController(c, new AddControllerCallback() { + @Override + public void onControllerAdded(final Controller controller) { + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + Snackbar.make(((ViewGroup) getActivity().getWindow().getDecorView().findViewById(android.R.id.content)) + .getChildAt(0), "Added Controller (" + controller.getId() + ")", Snackbar.LENGTH_LONG).show(); + } + }); + + dDaemon.getControllers().add(controller); + dismiss(); + } + + @Override + public void onAddFailed(final String msg, String detail) { + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + Snackbar.make(((ViewGroup) getActivity().getWindow().getDecorView().findViewById(android.R.id.content)) + .getChildAt(0), "Error: " + msg, Snackbar.LENGTH_LONG).show(); + } + }); + AddStripeDialog.instance.onResume(); + dismiss(); + } + + @Override + public void onConnectionFailed(final String message) { + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + Snackbar.make(((ViewGroup) getActivity().getWindow().getDecorView().findViewById(android.R.id.content)) + .getChildAt(0), "Coudn't connect to" + + " daemon at " + dDaemon + ": " + message, Snackbar.LENGTH_LONG).show(); + } + }); + AddStripeDialog.instance.onResume(); + dismiss(); + } + }); + } catch (JSONException | IOException e) { + e.printStackTrace(); + } + } + } + }); + } + + private static boolean isNumeric(String str) { + NumberFormat formatter = NumberFormat.getInstance(); + ParsePosition pos = new ParsePosition(0); + formatter.parse(str, pos); + return str.length() == pos.getIndex(); + } +} diff --git a/app/src/main/java/com/idlegandalf/ledd/fragments/AddDaemonDialog.java b/app/src/main/java/com/idlegandalf/ledd/fragments/AddDaemonDialog.java new file mode 100644 index 0000000..a5c2e9a --- /dev/null +++ b/app/src/main/java/com/idlegandalf/ledd/fragments/AddDaemonDialog.java @@ -0,0 +1,329 @@ +/* + * LEDD Project + * Copyright (C) 2015 LEDD Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.idlegandalf.ledd.fragments; + +import android.app.Dialog; +import android.app.DialogFragment; +import android.content.Context; +import android.content.DialogInterface; +import android.net.nsd.NsdManager; +import android.net.nsd.NsdServiceInfo; +import android.os.Bundle; +import android.support.design.widget.Snackbar; +import android.support.design.widget.TextInputLayout; +import android.support.v7.app.AlertDialog; +import android.text.Editable; +import android.text.TextWatcher; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.google.common.net.InetAddresses; +import com.idlegandalf.ledd.ColorActivity; +import com.idlegandalf.ledd.ColorApplication; +import com.idlegandalf.ledd.R; +import com.idlegandalf.ledd.callbacks.DiscoverCallback; +import com.idlegandalf.ledd.components.LedDDaemon; + +import org.json.JSONException; + +import java.io.IOException; +import java.net.Inet4Address; +import java.util.ArrayList; +import java.util.List; + +import butterknife.Bind; +import butterknife.ButterKnife; + + +public class AddDaemonDialog extends DialogFragment implements DialogInterface.OnShowListener, NsdManager.DiscoveryListener { + + private final String SERVICE_TYPE = "_ledd._tcp."; + @Bind(R.id.input_ip) + EditText ip; + @Bind(R.id.input_ip_layout) + TextInputLayout ip_lay; + @Bind(R.id.host_container) + LinearLayout hostContainer; + List ledDDaemons = new ArrayList<>(); + NsdManager mNsdManager; + private boolean mListening = false; + + public Dialog onCreateDialog(Bundle savedInstanceState) { + View v = View.inflate(getActivity(), R.layout.fragment_adddaemon, null); + ButterKnife.bind(this, v); + + mNsdManager = (NsdManager) getActivity().getApplicationContext().getSystemService(Context.NSD_SERVICE); + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + builder.setView(v).setPositiveButton("Add", null).setNegativeButton("Cancel", null); + + AlertDialog dialog = builder.create(); + + dialog.setOnShowListener(this); + + return dialog; + } + + @Override + public void onShow(final DialogInterface dialog) { + // start host discovery + if (!mListening) { + mNsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, this); + mListening = true; + } + + final AlertDialog alertDialog = (AlertDialog) dialog; + + ip.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + ip_lay.setError(null); + } + }); + + alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mNsdManager.stopServiceDiscovery(AddDaemonDialog.this); + AddStripeDialog.instance.onResume(); + alertDialog.dismiss(); + } + }); + + alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + String strIp = ip.getText().toString(); + int port; + + if (strIp.contains(":")) { + strIp = strIp.split(":")[0]; + try { + port = Integer.parseInt(ip.getText().toString().split(":")[1]); + } catch (NumberFormatException e) { + ip_lay.setError("Please check your port"); + return; + } + + if (port < 1024 || port > 65535) { + ip_lay.setError("Port is out of range"); + return; + } + } else { + port = 1425; + } + + if (InetAddresses.isInetAddress(strIp)) { + LedDDaemon daemon = new LedDDaemon(strIp, port); + + if (!ledDDaemons.contains(daemon)) addDaemon(new LedDDaemon(strIp, port)); + else ip_lay.setError("Daemon already exist"); + } else { + ip_lay.setError("No valid ip address"); + } + } + }); + } + + @Override + public void onStartDiscoveryFailed(String serviceType, int errorCode) { + Log.e(ColorApplication.TAG, "Discovery failed: Error code:" + errorCode); + mNsdManager.stopServiceDiscovery(this); + } + + @Override + public void onStopDiscoveryFailed(String serviceType, int errorCode) { + Log.e(ColorApplication.TAG, "Discovery failed: Error code:" + errorCode); + mNsdManager.stopServiceDiscovery(this); + mListening = false; + } + + @Override + public void onDiscoveryStarted(String serviceType) { + Log.d(ColorApplication.TAG, "Service discovery started"); + mListening = true; + } + + @Override + public void onDiscoveryStopped(String serviceType) { + Log.i(ColorApplication.TAG, "Discovery stopped: " + serviceType); + mListening = false; + } + + @Override + public void onServiceFound(NsdServiceInfo serviceInfo) { + Log.d(ColorApplication.TAG, "Service discovery success: " + serviceInfo); + if (serviceInfo.getServiceType().equals(SERVICE_TYPE)) { + mNsdManager.resolveService(serviceInfo, new NsdManager.ResolveListener() { + @Override + public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) { + Log.e(ColorApplication.TAG, "Resolve failed: " + errorCode); + } + + @Override + public void onServiceResolved(final NsdServiceInfo serviceInfo) { + Log.e(ColorApplication.TAG, "Resolve Succeeded. " + serviceInfo); + + if (serviceInfo.getHost() instanceof Inet4Address) { + final LedDDaemon nLedDDaemon = new LedDDaemon(serviceInfo.getHost().getHostAddress(), serviceInfo.getPort()); + + if (!ledDDaemons.contains(nLedDDaemon)) { + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + View v = ((LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout + .host_row, hostContainer, false); + + + TextView host = (TextView) v.findViewById(R.id.text_host); + + host.setText(nLedDDaemon.toString()); + + if (ColorApplication.getInstance().getDaemons().contains(nLedDDaemon)) { + v.setEnabled(false); + host.setEnabled(false); + } + + View.OnClickListener listener = new View.OnClickListener() { + @Override + public void onClick(View v) { + if (v.isEnabled()) { + LedDDaemon d; + + if (v instanceof TextView) { + d = (LedDDaemon) ((LinearLayout) v.getParent()).getTag(); + } else { + d = (LedDDaemon) v.getTag(); + } + + if (d != null) { + addDaemon(d); + } + } + } + }; + + v.setOnClickListener(listener); + host.setOnClickListener(listener); + + v.setTag(nLedDDaemon); + + ledDDaemons.add(nLedDDaemon); + hostContainer.addView(v); + } + }); + } + } + } + }); + } else { + Log.d(ColorApplication.TAG, "Unknown Service Type: " + serviceInfo.getServiceType()); + } + } + + @Override + public void onServiceLost(NsdServiceInfo serviceInfo) { + Log.e(ColorApplication.TAG, "service lost" + serviceInfo); + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (mNsdManager != null && mListening) { + mNsdManager.stopServiceDiscovery(this); + mListening = false; + } + } + + @Override + public void onPause() { + super.onPause(); + + if (mNsdManager != null && mListening) { + mNsdManager.stopServiceDiscovery(this); + mListening = false; + } + } + + @Override + public void onResume() { + super.onResume(); + + if (mNsdManager != null && !mListening) { + mNsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, this); + mListening = true; + } + } + + private void addDaemon(final LedDDaemon ledDDaemon) { + try { + ColorApplication.getInstance().getHelperForDaemon(ledDDaemon).discover(new DiscoverCallback() { + @Override + public void onConnectionFailed(final String message) { + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + Snackbar.make(((ViewGroup) getActivity().getWindow().getDecorView().findViewById(android.R.id.content)).getChildAt(0), + "Coudn't connect to" + + " daemon at " + ledDDaemon + ": " + message, Snackbar.LENGTH_LONG).show(); + } + }); + AddStripeDialog stripeAdd = (AddStripeDialog) getFragmentManager().findFragmentByTag("stripeAdd"); + AddStripeDialog.instance.onResume(); + dismiss(); + } + + @Override + public void onDiscoverSuccessfully(final String version) { + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + Snackbar.make(((ViewGroup) getActivity().getWindow().getDecorView().findViewById(android.R.id.content)).getChildAt(0), + "Added LedD Daemon version: " + version, Snackbar.LENGTH_LONG).show(); + } + }); + + try { + ((ColorActivity) getActivity()).refreshStripes(); + } catch (IOException e) { + e.printStackTrace(); + } + AddStripeDialog.instance.onResume(); + dismiss(); + } + }); + } catch (JSONException | IOException e) { + e.printStackTrace(); + } + } +} diff --git a/app/src/main/java/com/idlegandalf/ledd/fragments/AddStripeDialog.java b/app/src/main/java/com/idlegandalf/ledd/fragments/AddStripeDialog.java new file mode 100644 index 0000000..9979d0f --- /dev/null +++ b/app/src/main/java/com/idlegandalf/ledd/fragments/AddStripeDialog.java @@ -0,0 +1,457 @@ +/* + * LEDD Project + * Copyright (C) 2015 LEDD Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.idlegandalf.ledd.fragments; + + +import android.app.Dialog; +import android.app.DialogFragment; +import android.content.DialogInterface; +import android.os.Bundle; +import android.support.design.widget.Snackbar; +import android.support.design.widget.TextInputLayout; +import android.support.v7.app.AlertDialog; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.EditText; +import android.widget.ImageButton; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.Spinner; +import android.widget.Toast; + +import com.google.gson.Gson; +import com.idlegandalf.ledd.ColorActivity; +import com.idlegandalf.ledd.ColorApplication; +import com.idlegandalf.ledd.R; +import com.idlegandalf.ledd.callbacks.AddStripeCallback; +import com.idlegandalf.ledd.callbacks.StripesCallback; +import com.idlegandalf.ledd.components.Controller; +import com.idlegandalf.ledd.components.LedDDaemon; +import com.idlegandalf.ledd.components.LedStripe; +import com.idlegandalf.ledd.helper.LedDHelper; + +import org.json.JSONException; + +import java.io.IOException; +import java.text.NumberFormat; +import java.text.ParsePosition; +import java.util.List; + +import butterknife.Bind; +import butterknife.ButterKnife; +import butterknife.OnClick; + +public class AddStripeDialog extends DialogFragment implements DialogInterface.OnShowListener { + + public static AddStripeDialog instance; + @Bind(R.id.spinner_daemon) + Spinner daemonSpinner; + @Bind(R.id.spinner_controller) + Spinner controllerSpinner; + @Bind(R.id.choose_controller_lay) + RelativeLayout controllerLayout; + @Bind(R.id.input_stripe_name_lay) + TextInputLayout stripeNameLay; + @Bind(R.id.input_stripe_name) + EditText stripeNameText; + @Bind(R.id.input_channel_r_lay) + TextInputLayout channelRLay; + @Bind(R.id.input_channel_r) + EditText channelR; + @Bind(R.id.input_channel_g_lay) + TextInputLayout channelGLay; + @Bind(R.id.input_channel_g) + EditText channelG; + @Bind(R.id.input_channel_b_lay) + TextInputLayout channelBLay; + @Bind(R.id.input_channel_b) + EditText channelB; + @Bind(R.id.stripe_mapping_lay) + LinearLayout stripeMapping; + @Bind(R.id.imgbuttn_togglechannel_r) + ImageButton channelRBttn; + @Bind(R.id.imgbuttn_togglechannel_g) + ImageButton channelGBttn; + @Bind(R.id.imgbuttn_togglechannel_b) + ImageButton channelBBttn; + ArrayAdapter daemonArrayAdapter; + ArrayAdapter controllerArrayAdapter; + boolean mDaemonSelected = false; + boolean mControllerSelected = false; + + private static boolean isNumeric(String str) { + NumberFormat formatter = NumberFormat.getInstance(); + ParsePosition pos = new ParsePosition(0); + formatter.parse(str, pos); + return str.length() == pos.getIndex(); + } + + public Dialog onCreateDialog(Bundle savedInstanceState) { + View v = View.inflate(getActivity(), R.layout.fragment_addstripe, null); + ButterKnife.bind(this, v); + instance = this; + + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + builder.setView(v).setPositiveButton("Add", null).setNegativeButton("Cancel", null); + + AlertDialog dialog = builder.create(); + + dialog.setOnShowListener(this); + + return dialog; + } + + @Override + public void onShow(final DialogInterface dialog) { + + final AlertDialog alertDialog = (AlertDialog) dialog; + toggleAll(controllerLayout, false); + channelRBttn.setEnabled(false); + channelGBttn.setEnabled(false); + channelBBttn.setEnabled(false); + + stripeNameText.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + stripeNameLay.setError(null); + } + }); + + channelR.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + if (s.toString().isEmpty()) { + channelRBttn.setEnabled(false); + } else { + channelRBttn.setEnabled(true); + } + } + }); + channelG.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + if (s.toString().isEmpty()) { + channelGBttn.setEnabled(false); + } else { + channelGBttn.setEnabled(true); + } + } + }); + channelB.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + if (s.toString().isEmpty()) { + channelBBttn.setEnabled(false); + } else { + channelBBttn.setEnabled(true); + } + } + }); + + ImageButton.OnClickListener imgListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.imgbuttn_togglechannel_r: + testChannel(channelR, (ImageButton) v); + break; + case R.id.imgbuttn_togglechannel_g: + testChannel(channelG, (ImageButton) v); + break; + case R.id.imgbuttn_togglechannel_b: + testChannel(channelB, (ImageButton) v); + break; + } + } + }; + + channelRBttn.setOnClickListener(imgListener); + channelGBttn.setOnClickListener(imgListener); + channelBBttn.setOnClickListener(imgListener); + + alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + alertDialog.dismiss(); + } + }); + + alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (!mDaemonSelected) { + Toast.makeText(getActivity(), "Please select Daemon and Controller", Toast.LENGTH_LONG).show(); + return; + } + + if (stripeNameText.getText().toString().isEmpty()) { + stripeNameLay.setError("Please set the Stripe name"); + return; + } + + if (channelR.getText().toString().isEmpty() || channelG.getText().toString().isEmpty() || channelB.getText().toString().isEmpty()) { + Toast.makeText(getActivity(), "Please add mapping for all channels", Toast.LENGTH_LONG).show(); + return; + } + + LedStripe stripe = new LedStripe(Integer.parseInt(channelR.getText().toString()), Integer.parseInt(channelG.getText().toString()), + Integer.parseInt(channelB.getText().toString()), stripeNameText.getText().toString()); + stripe.setLedDDaemon((LedDDaemon) daemonSpinner.getSelectedItem()); + stripe.setController((Controller) controllerSpinner.getSelectedItem()); + + LedDHelper helper = null; + try { + helper = ColorApplication.getInstance().getHelperForDaemon((LedDDaemon) daemonSpinner.getSelectedItem()); + } catch (IOException e) { + e.printStackTrace(); + } + + if (helper != null) { + try { + helper.addStripe(stripe, new AddStripeCallback() { + @Override + public void onAddSuccessfully(final LedStripe stripe) { + ColorActivity activity = ((ColorActivity) getActivity()); + try { + activity.refreshStripes(); + } catch (IOException e) { + e.printStackTrace(); + } + + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + Snackbar.make(((ViewGroup) getActivity().getWindow().getDecorView().findViewById(android.R.id.content)) + .getChildAt(0), "Added stripe (" + stripe.getId() + ")", Snackbar.LENGTH_LONG).show(); + } + }); + dismiss(); + } + + @Override + public void onConnectionFailed(final String message) { + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + Snackbar.make(((ViewGroup) getActivity().getWindow().getDecorView().findViewById(android.R.id.content)) + .getChildAt(0), "Failed to add stripe: " + message, Snackbar.LENGTH_LONG).show(); + } + }); + dismiss(); + } + }); + } catch (JSONException | IOException e) { + e.printStackTrace(); + } + } + } + }); + + daemonArrayAdapter = new ArrayAdapter<>(getActivity().getApplicationContext(), R.layout.spinner_item); + daemonArrayAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item); + daemonArrayAdapter.addAll(ColorApplication.getInstance().getDaemons()); + + controllerArrayAdapter = new ArrayAdapter<>(getActivity().getApplicationContext(), R.layout.spinner_item); + controllerArrayAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item); + + daemonSpinner.setAdapter(daemonArrayAdapter); + controllerSpinner.setAdapter(controllerArrayAdapter); + + daemonSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + mDaemonSelected = true; + toggleAll(controllerLayout, true); + refreshController((LedDDaemon) daemonSpinner.getSelectedItem()); + } + + @Override + public void onNothingSelected(AdapterView parent) { + toggleAll(controllerLayout, false); + controllerArrayAdapter.clear(); + mDaemonSelected = false; + mControllerSelected = false; + } + }); + + controllerSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + mControllerSelected = true; + } + + @Override + public void onNothingSelected(AdapterView parent) { + mControllerSelected = false; + } + }); + } + + @OnClick(R.id.imgbuttn_addcontroller) + public void addController(ImageButton button) { + AddControllerDialog dialog = new AddControllerDialog(); + Bundle b = new Bundle(); + b.putString("daemon", new Gson().toJson(daemonSpinner.getSelectedItem())); + dialog.setArguments(b); + dialog.show(getActivity().getFragmentManager(), ""); + } + + @OnClick(R.id.imgbuttn_adddaemon) + public void addDaemon(ImageButton button) { + new AddDaemonDialog().show(getActivity().getFragmentManager(), ""); + } + + private void toggleAll(ViewGroup v, boolean status) { + for (int i = 0; i < v.getChildCount(); i++) { + v.getChildAt(i).setEnabled(status); + } + } + + @Override + public void onResume() { + super.onResume(); + ColorApplication.getInstance().onResume(); + if (daemonArrayAdapter != null) { + daemonArrayAdapter.clear(); + daemonArrayAdapter.addAll(ColorApplication.getInstance().getDaemons()); + } + + if (controllerArrayAdapter != null && mDaemonSelected) { + refreshController((LedDDaemon) daemonSpinner.getSelectedItem()); + } + } + + private void testChannel(EditText text, ImageButton button) { + if (mDaemonSelected && mControllerSelected) { + if (!text.getText().toString().isEmpty() && isNumeric(text.getText().toString())) { + int val; + boolean toggle = false; + if (text.getTag() != null) toggle = (boolean) text.getTag(); + if (!toggle) { + val = 1; + toggle = true; + button.setImageResource(R.drawable.ic_visibility_black_48dp); + } else { + val = 0; + toggle = false; + button.setImageResource(R.drawable.ic_visibility_off_black_48dp); + } + text.setTag(toggle); + + LedDHelper helper = null; + try { + helper = ColorApplication.getInstance().getHelperForDaemon((LedDDaemon) daemonSpinner.getSelectedItem()); + } catch (IOException e) { + e.printStackTrace(); + } + + if (helper != null) { + try { + helper.testChannel((Controller) controllerSpinner.getSelectedItem(), Integer.parseInt(text.getText().toString()), val); + } catch (JSONException e) { + e.printStackTrace(); + } + } + } + } + } + + private void refreshController(final LedDDaemon ledDDaemon) { + controllerArrayAdapter.clear(); + LedDHelper helper = null; + try { + helper = ColorApplication.getInstance().getHelperForDaemon(ledDDaemon); + } catch (IOException e) { + e.printStackTrace(); + } + + if (helper != null) { + try { + helper.getStripes(new StripesCallback() { + @Override + public void onSuccess(List stripes) { + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + controllerArrayAdapter.addAll(ledDDaemon.getControllers()); + toggleAll(stripeMapping, true); + } + }); + } + + @Override + public void onGetFailed(String message) { + + } + + @Override + public void onConnectionFailed(String message) { + + } + }); + } catch (JSONException | IOException e) { + e.printStackTrace(); + } + } + } +} diff --git a/app/src/main/java/com/idlegandalf/ledd/fragments/DrawerFragment.java b/app/src/main/java/com/idlegandalf/ledd/fragments/DrawerFragment.java deleted file mode 100644 index c2fe20d..0000000 --- a/app/src/main/java/com/idlegandalf/ledd/fragments/DrawerFragment.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * LEDD Project - * Copyright (C) 2015 LEDD Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.idlegandalf.ledd.fragments; - -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.LinearLayout; - -import com.idlegandalf.ledd.R; - -import butterknife.Bind; -import butterknife.ButterKnife; -import butterknife.OnClick; - -public class DrawerFragment extends Fragment { - @Bind(R.id.lay_add_host) - LinearLayout addHost; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View v = inflater.inflate(R.layout.drawer_fragment, container, false); - ButterKnife.bind(this, v); - - return v; - } - - @OnClick(R.id.lay_add_host) - public void addHost() { - // TODO: add dialog with selection and input things - } -} diff --git a/app/src/main/java/com/idlegandalf/ledd/helper/LedDHelper.java b/app/src/main/java/com/idlegandalf/ledd/helper/LedDHelper.java index a95275f..78fd9f9 100644 --- a/app/src/main/java/com/idlegandalf/ledd/helper/LedDHelper.java +++ b/app/src/main/java/com/idlegandalf/ledd/helper/LedDHelper.java @@ -23,49 +23,65 @@ import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.IBinder; +import android.util.Log; +import com.idlegandalf.ledd.ColorApplication; import com.idlegandalf.ledd.callbacks.AddControllerCallback; +import com.idlegandalf.ledd.callbacks.AddStripeCallback; +import com.idlegandalf.ledd.callbacks.DiscoverCallback; import com.idlegandalf.ledd.callbacks.RecieveColorCallback; +import com.idlegandalf.ledd.callbacks.StripesCallback; import com.idlegandalf.ledd.components.AnswerTask; +import com.idlegandalf.ledd.components.Controller; import com.idlegandalf.ledd.components.HSV; -import com.idlegandalf.ledd.components.Host; +import com.idlegandalf.ledd.components.LedDDaemon; +import com.idlegandalf.ledd.components.LedDRequest; +import com.idlegandalf.ledd.components.LedStripe; import com.idlegandalf.ledd.services.ColorService; +import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; - -import hugo.weaving.DebugLog; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.LinkedBlockingQueue; public class LedDHelper { final String ACTION_SETCOLOR = "set_color"; final String ACTION_GETCOLOR = "get_color"; final String ACTION_ADDCONTROLLER = "add_controller"; - final String ACTION_GETCONTROLLER = "get_controller"; - final String ACTION_ADDSTRIPES = "add_stripes"; - private Host host; + final String ACTION_GETALLSTRIPES = "get_stripes"; + final String ACTION_ADDSTRIPES = "add_stripe"; + final String ACTION_TESTCHANNEL = "test_channel"; + final String ACTION_DISCOVER = "discover"; private Context context; - private ColorService.ColorBinder binderService; private boolean mBound = false; + private LedDDaemon ledDDaemon; + private Worker requestWorker; + private LinkedBlockingQueue dRequests; ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName className, IBinder service) { - System.out.println("service bound!"); - binderService = (ColorService.ColorBinder) service; + Log.d(ColorApplication.TAG, "ColorService bound!"); + requestWorker = new Worker<>(dRequests, (ColorService.ColorBinder) service, ledDDaemon); mBound = true; + new Thread(requestWorker).start(); } @Override public void onServiceDisconnected(ComponentName arg0) { + requestWorker.stop(); mBound = false; } }; - public LedDHelper(Host host, Context appl) throws IOException { - this.host = host; + public LedDHelper(LedDDaemon ledDDaemon, Context appl) throws IOException { this.context = appl; + this.dRequests = new LinkedBlockingQueue<>(); + this.ledDDaemon = ledDDaemon; Intent intent = new Intent(appl, ColorService.class); appl.bindService(intent, mConnection, Context.BIND_AUTO_CREATE); @@ -74,25 +90,30 @@ public class LedDHelper { /** * Add controller to ledd daemon * - * @param channels channel amount that this controller holds - * @param i2c_dev number of i2c device, e.g. /dev/i2c-1 would be 1 + * @param c controller object * @throws JSONException no valid json * @throws IOException socket error */ - public void addController(int channels, int i2c_dev, String address, final AddControllerCallback callback) throws JSONException, IOException { + public void addController(final Controller c, final AddControllerCallback callback) throws JSONException, IOException { JSONObject jnson = new JSONObject(); jnson.put("action", ACTION_ADDCONTROLLER); - jnson.put("channels", channels); - jnson.put("i2c_dev", i2c_dev); - jnson.put("address", address); + jnson.put("channels", c.getChannels()); + jnson.put("i2c_dev", c.getI2c_device()); + jnson.put("address", c.getAddress()); - sendJSON(jnson, new AnswerTask() { + addRequestToQueue(jnson, new AnswerTask() { @Override - public void run() { + public void onConnectionFailed(String message) { + callback.onAddFailed(message, ""); + } + + @Override + public void onResponse(JSONObject response) { try { if (response.getBoolean("success")) { - callback.onControllerAdded(response.getInt("cid")); + c.setId(response.getInt("cid")); + callback.onControllerAdded(c); } else { callback.onAddFailed(response.getString("message"), response.getString("message_detail")); } @@ -104,51 +125,123 @@ public class LedDHelper { } /** - * Set color using the stripeid + * Get stripes known to daemon * - * @param sid Stripeid - * @param color Color in HSV format * @throws JSONException no valid json * @throws IOException socket error */ - public void setColor(int sid, HSV color) throws JSONException, IOException { + public void getStripes(final StripesCallback callback) throws JSONException, IOException { + JSONObject jnson = new JSONObject(); + + jnson.put("action", ACTION_GETALLSTRIPES); + + addRequestToQueue(jnson, new AnswerTask() { + @Override + public void onConnectionFailed(String message) { + callback.onGetFailed(message); + } + + @Override + public void onResponse(JSONObject response) { + try { + if (response.getBoolean("success")) { + ledDDaemon.getControllers().clear(); + List list = new ArrayList<>(); + JSONArray jcontrollers = response.getJSONArray("controller"); + + for (int i = 0; i < jcontrollers.length(); i++) { + JSONObject row = jcontrollers.getJSONObject(i); + Controller nController = new Controller(); + nController.setAddress(row.getString("address")); + nController.setChannels(row.getInt("channel")); + nController.setI2c_device(row.getInt("i2c_device")); + nController.setId(row.getInt("id")); + + JSONArray jstripes = row.getJSONArray("stripes"); + + for (int o = 0; o < jstripes.length(); o++) { + JSONObject srow = jstripes.getJSONObject(i); + LedStripe nStripe = new LedStripe(); + nStripe.setId(srow.getInt("id")); + nStripe.setRGB(srow.getBoolean("rgb")); + nStripe.setChannelRed(srow.getJSONArray("channel").getInt(0)); + nStripe.setChannelGreen(srow.getJSONArray("channel").getInt(1)); + nStripe.setChannelBlue(srow.getJSONArray("channel").getInt(2)); + nStripe.setName(srow.getString("name")); + nStripe.setController(nController); + nStripe.setLedDDaemon(ledDDaemon); + list.add(nStripe); + } + + ledDDaemon.getControllers().add(nController); + } + + callback.onSuccess(list); + } else { + if (response.has("message")) callback.onGetFailed(response.getString("message")); + else callback.onGetFailed("unknown error"); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + + /** + * Set color using the stripeid + * + * @param ledStripe Stripe + */ + public void setColor(LedStripe ledStripe) { + JSONObject jnson = new JSONObject(); JSONObject hsv = new JSONObject(); - hsv.put("h", color.getHue()); - hsv.put("s", color.getSaturation()); - hsv.put("v", color.getValue()); + try { + hsv.put("h", ledStripe.getColor().getHue()); + hsv.put("s", ledStripe.getColor().getSaturation()); - jnson.put("action", ACTION_SETCOLOR); - jnson.put("sid", sid); - jnson.put("color", hsv); + hsv.put("v", ledStripe.getColor().getValue()); - sendJSON(jnson, null); + + jnson.put("action", ACTION_SETCOLOR); + jnson.put("sid", ledStripe.getId()); + jnson.put("hsv", hsv); + + } catch (JSONException e) { + e.printStackTrace(); + } + + addRequestToQueue(jnson, null); } /** * Get color using the stripeid * - * @param sid Stripeid + * @param ledStripe Stripe * @throws JSONException no valid json * @throws IOException socket error */ - public void getColor(int sid, final RecieveColorCallback callback) throws JSONException, IOException { + public void getColor(final LedStripe ledStripe, final RecieveColorCallback callback) throws JSONException, IOException { JSONObject jnson = new JSONObject(); jnson.put("action", ACTION_GETCOLOR); - jnson.put("sid", sid); + jnson.put("sid", ledStripe.getId()); - sendJSON(jnson, new AnswerTask() { + addRequestToQueue(jnson, new AnswerTask() { @Override - public void run() { + public void onConnectionFailed(String message) { + callback.onRecievFailed(message); + } + + @Override + public void onResponse(JSONObject response) { try { if (response.getBoolean("success")) { - - JSONObject hsv = null; - - hsv = response.getJSONObject("hsv"); - callback.onColorRecieved(new HSV(hsv.getDouble("h"), hsv.getDouble("s"), hsv.getDouble("v"))); + JSONArray hsv = response.getJSONArray("color"); + ledStripe.setColor(new HSV(hsv.getDouble(0), hsv.getDouble(1), hsv.getDouble(2))); + callback.onColorRecieved(ledStripe); } else { callback.onRecievFailed(response.getString("message")); } @@ -159,15 +252,151 @@ public class LedDHelper { }); } - private void sendJSON(JSONObject json, AnswerTask task) throws IOException, JSONException { - if (mBound) binderService.queueSend(host, json, task); + /** + * Test a channel on the controller + * + * @param c controller + * @param channel channel number + * @param value value (1= on, 0 = off) + * @throws JSONException + */ + public void testChannel(Controller c, int channel, int value) throws JSONException { + JSONObject jnson = new JSONObject(); + + jnson.put("action", ACTION_TESTCHANNEL); + jnson.put("cid", c.getId()); + jnson.put("channel", channel); + jnson.put("value", value); + + addRequestToQueue(jnson, new AnswerTask() { + @Override + public void onConnectionFailed(String message) { + + } + + @Override + public void onResponse(JSONObject response) { + + } + }); + } + + /** + * Get information about an ledd daemon + * + * @throws JSONException no valid json + * @throws IOException socket error + */ + public void discover(final DiscoverCallback callback) throws JSONException, IOException { + JSONObject jnson = new JSONObject(); + + jnson.put("action", ACTION_DISCOVER); + + addRequestToQueue(jnson, new AnswerTask() { + @Override + public void onConnectionFailed(String message) { + callback.onConnectionFailed(message); + } + + @Override + public void onResponse(JSONObject response) { + try { + if (response.getBoolean("success")) { + callback.onDiscoverSuccessfully(response.getString("version")); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + + /** + * Get information about an ledd daemon + * + * @throws JSONException no valid json + * @throws IOException socket error + */ + public void addStripe(final LedStripe ledStripe, final AddStripeCallback callback) throws JSONException, IOException { + JSONObject jnson = new JSONObject(); + + jnson.put("action", ACTION_ADDSTRIPES); + JSONObject stripe = new JSONObject(); + + stripe.put("name", ledStripe.getName()); + stripe.put("rgb", ledStripe.isRGB()); + + JSONObject mapping = new JSONObject(); + mapping.put("r", ledStripe.getChannelRed()); + mapping.put("g", ledStripe.getChannelGreen()); + mapping.put("b", ledStripe.getChannelBlue()); + stripe.put("map", mapping); + stripe.put("cid", ledStripe.getController().getId()); + jnson.put("stripe", stripe); + + addRequestToQueue(jnson, new AnswerTask() { + @Override + public void onConnectionFailed(String message) { + callback.onConnectionFailed(message); + } + + @Override + public void onResponse(JSONObject response) { + try { + if (response.getBoolean("success")) { + ledStripe.setId(response.getInt("sid")); + callback.onAddSuccessfully(ledStripe); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + + private void addRequestToQueue(JSONObject json, AnswerTask task) { + dRequests.add(new LedDRequest(json, task)); } - @DebugLog public void teardown() { if (mBound) { context.unbindService(mConnection); mBound = false; } + requestWorker.stop(); + } + + private static class Worker implements Runnable { + private final LinkedBlockingQueue workQueue; + private final ColorService.ColorBinder binder; + private final LedDDaemon ledDDaemon; + + public Worker(LinkedBlockingQueue workQueue, ColorService.ColorBinder colorBinder, LedDDaemon dDaemon) { + this.workQueue = workQueue; + this.binder = colorBinder; + this.ledDDaemon = dDaemon; + } + + @Override + public void run() { + while (!Thread.currentThread().isInterrupted()) { + try { + final T item = workQueue.take(); + + if (item instanceof LedDRequest) { + binder.queueSend(ledDDaemon, ((LedDRequest) item).getRequest(), ((LedDRequest) item).getTask()); + } + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + break; + } catch (JSONException e) { + e.printStackTrace(); + } + } + } + + public void stop() { + Thread.currentThread().interrupt(); + } } } diff --git a/app/src/main/java/com/idlegandalf/ledd/services/ColorService.java b/app/src/main/java/com/idlegandalf/ledd/services/ColorService.java index 59ba9a7..06d141b 100644 --- a/app/src/main/java/com/idlegandalf/ledd/services/ColorService.java +++ b/app/src/main/java/com/idlegandalf/ledd/services/ColorService.java @@ -24,7 +24,7 @@ import android.os.Binder; import android.os.IBinder; import com.idlegandalf.ledd.components.AnswerTask; -import com.idlegandalf.ledd.components.Host; +import com.idlegandalf.ledd.components.LedDDaemon; import com.idlegandalf.ledd.components.Sendable; import com.koushikdutta.async.AsyncServer; import com.koushikdutta.async.AsyncSocket; @@ -41,10 +41,12 @@ import java.io.UnsupportedEncodingException; import java.net.InetSocketAddress; import java.util.HashMap; import java.util.concurrent.LinkedBlockingQueue; - -import hugo.weaving.DebugLog; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; public class ColorService extends Service { + private static ScheduledThreadPoolExecutor poolExecutor = new ScheduledThreadPoolExecutor(5); private final IBinder mBinder = new ColorBinder(); private LinkedBlockingQueue queue; private Worker worker; @@ -63,15 +65,22 @@ public class ColorService extends Service { return mBinder; } + @Override + public boolean onUnbind(Intent intent) { + return super.onUnbind(intent); + } + @Override public void onDestroy() { worker.stop(); + poolExecutor.shutdownNow(); } private static class Worker implements Runnable { private final LinkedBlockingQueue workQueue; - private HashMap socketHashMap; + private HashMap socketHashMap; private HashMap sendableHashMap; + private HashMap timeoutHashMap; DataCallback dataCallback = new DataCallback() { @Override @@ -88,6 +97,9 @@ public class ColorService extends Service { if (sendableHashMap.containsKey(resp.getString("ref"))) { sendableHashMap.get(resp.getString("ref")).onResponse(resp); sendableHashMap.remove(resp.getString("ref")); + if (timeoutHashMap.containsKey(resp.getString("ref")) && timeoutHashMap.get(resp.getString("ref")) != null) + timeoutHashMap.get(resp.getString("ref")).cancel(false); + timeoutHashMap.remove(resp.getString("ref")); } } catch (JSONException e) { e.printStackTrace(); @@ -100,10 +112,10 @@ public class ColorService extends Service { this.workQueue = workQueue; this.socketHashMap = new HashMap<>(); this.sendableHashMap = new HashMap<>(); + this.timeoutHashMap = new HashMap<>(); } @Override - @DebugLog public void run() { while (!Thread.currentThread().isInterrupted()) { try { @@ -113,9 +125,19 @@ public class ColorService extends Service { if (socketHashMap.containsKey(((Sendable) item).getRecipient()) && socketHashMap.get(((Sendable) item).getRecipient()) .getServer().isRunning()) { - Util.writeAll(socketHashMap.get(((Sendable) item).getRecipient()), ((Sendable) item).getMessage().toString().getBytes + Util.writeAll(socketHashMap.get(((Sendable) item).getRecipient()), (((Sendable) item).getMessage().toString() + "\n") + .getBytes ("UTF-8"), null); sendableHashMap.put(((Sendable) item).getRef(), (Sendable) item); + if (!poolExecutor.isTerminating() && !poolExecutor.isTerminated()) + timeoutHashMap.put(((Sendable) item).getRef(), poolExecutor.schedule(new Runnable() { + @Override + public void run() { + ((Sendable) item).onNoResponse(); + timeoutHashMap.remove(((Sendable) item).getRef()); + sendableHashMap.remove(((Sendable) item).getRef()); + } + }, 1000, TimeUnit.MILLISECONDS)); } else { AsyncServer.getDefault().connectSocket(new InetSocketAddress(((Sendable) item).getRecipient().getAddress(), ((Sendable) item).getRecipient().getPort()), new ConnectCallback() { @@ -126,11 +148,10 @@ public class ColorService extends Service { socketHashMap.put(((Sendable) item).getRecipient(), socket); - if (!workQueue.contains(item)) { - workQueue.add(item); - } + //if (!workQueue.contains(item)) -> needs equals implementaion + workQueue.add(item); } else { - ex.printStackTrace(); + ((Sendable) item).onConnectionFailed(ex.getMessage()); } } }); @@ -151,10 +172,9 @@ public class ColorService extends Service { } public class ColorBinder extends Binder { - public String queueSend(Host rec, JSONObject msg, AnswerTask answerTask) throws JSONException { + public String queueSend(LedDDaemon rec, JSONObject msg, AnswerTask answerTask) throws JSONException { Sendable sendable = new Sendable(msg, answerTask, rec); queue.add(sendable); - System.out.println("qlen: " + queue.size()); return sendable.getRef(); } } diff --git a/app/src/main/res/layout/activity_color.xml b/app/src/main/res/layout/activity_color.xml index 37e88f6..758b7e6 100644 --- a/app/src/main/res/layout/activity_color.xml +++ b/app/src/main/res/layout/activity_color.xml @@ -19,9 +19,10 @@ + android:layout_height="match_parent" + android:fitsSystemWindows="true"> @@ -38,21 +39,29 @@ android:background="?attr/colorPrimary" android:minHeight="?android:attr/actionBarSize"/> - + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:layout_marginTop="25dp"/> + + - + app:headerLayout="@layout/navigation_header" + app:menu="@menu/navigation_drawer"/> \ No newline at end of file diff --git a/app/src/main/res/layout/drawer_fragment.xml b/app/src/main/res/layout/drawer_fragment.xml deleted file mode 100644 index 7cf765f..0000000 --- a/app/src/main/res/layout/drawer_fragment.xml +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/fragment_addcontroller.xml b/app/src/main/res/layout/fragment_addcontroller.xml new file mode 100644 index 0000000..edad69e --- /dev/null +++ b/app/src/main/res/layout/fragment_addcontroller.xml @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_adddaemon.xml b/app/src/main/res/layout/fragment_adddaemon.xml new file mode 100644 index 0000000..72d1bab --- /dev/null +++ b/app/src/main/res/layout/fragment_adddaemon.xml @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_addstripe.xml b/app/src/main/res/layout/fragment_addstripe.xml new file mode 100644 index 0000000..87a9639 --- /dev/null +++ b/app/src/main/res/layout/fragment_addstripe.xml @@ -0,0 +1,275 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/host_row.xml b/app/src/main/res/layout/host_row.xml index e05d5a4..3d3db90 100644 --- a/app/src/main/res/layout/host_row.xml +++ b/app/src/main/res/layout/host_row.xml @@ -18,21 +18,31 @@ --> + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="5dp" + android:background="?android:attr/selectableItemBackground" + android:clickable="true" + android:gravity="center_horizontal" + android:orientation="horizontal" + android:paddingLeft="7dp"> + + + android:textAppearance="?android:textAppearanceMedium" + android:textColor="@color/primaryColorDark"/> \ No newline at end of file diff --git a/app/src/main/res/layout/navigation_header.xml b/app/src/main/res/layout/navigation_header.xml new file mode 100644 index 0000000..7d4688a --- /dev/null +++ b/app/src/main/res/layout/navigation_header.xml @@ -0,0 +1,35 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/spinner_dropdown_item.xml b/app/src/main/res/layout/spinner_dropdown_item.xml new file mode 100644 index 0000000..8a662f2 --- /dev/null +++ b/app/src/main/res/layout/spinner_dropdown_item.xml @@ -0,0 +1,28 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/spinner_item.xml b/app/src/main/res/layout/spinner_item.xml new file mode 100644 index 0000000..0dee485 --- /dev/null +++ b/app/src/main/res/layout/spinner_item.xml @@ -0,0 +1,29 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/navigation_drawer.xml b/app/src/main/res/menu/navigation_drawer.xml new file mode 100644 index 0000000..ce872d8 --- /dev/null +++ b/app/src/main/res/menu/navigation_drawer.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/build.gradle b/build.gradle index 1b7886d..aac6a05 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,21 @@ +/* + * LEDD Project + * Copyright (C) 2015 LEDD Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { @@ -5,7 +23,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:1.3.0' + classpath 'com.android.tools.build:gradle:1.3.1' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files