reworked a whole bunch of stuff

moved from assistant to one single activity model with dialogs and navigation drawer as main content holder
completed separate threaded queue based service to communicate with daemon(s)
added first few elements to the nav drawer
This commit is contained in:
Giovanni Harting
2015-09-01 05:56:48 +02:00
parent ab8b864bee
commit aaa9c5da02
51 changed files with 677 additions and 2037 deletions

View File

@@ -15,13 +15,13 @@ apply plugin: 'com.jakewharton.hugo'
apply plugin: 'com.github.ben-manes.versions' apply plugin: 'com.github.ben-manes.versions'
android { android {
compileSdkVersion 22 compileSdkVersion 23
buildToolsVersion "22.0.1" buildToolsVersion '23.0.0'
defaultConfig { defaultConfig {
applicationId "com.idlegandalf.ledd" applicationId "com.idlegandalf.ledd"
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 22 targetSdkVersion 23
versionCode 1 versionCode 1
versionName "1.0" versionName "1.0"
} }
@@ -34,12 +34,14 @@ android {
} }
dependencies { dependencies {
compile fileTree(dir: 'libs', include: ['*.jar']) compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.android.support:appcompat-v7:22.2.1' compile 'com.android.support:appcompat-v7:23.0.0'
compile 'com.android.support:support-v4:22.2.1' compile 'com.android.support:support-v4:23.0.0'
compile 'com.squareup.okhttp:okhttp:2.4.0' 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.jakewharton:butterknife:7.0.1'
compile 'com.koushikdutta.async:androidasync:2.1.6' compile 'com.koushikdutta.async:androidasync:2.1.6'
compile 'com.android.support:design:22.2.1' compile 'com.android.support:design:23.0.0'
provided "org.projectlombok:lombok:1.16.4" compile 'com.rarepebble:colorpicker:1.3.0'
provided 'org.projectlombok:lombok:1.16.6'
} }

View File

@@ -1,13 +1,14 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest
package="com.idlegandalf.ledd"> package="com.idlegandalf.ledd"
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<application <application
android:name="com.idlegandalf.ledd.ColorApplication" android:name=".ColorApplication"
android:allowBackup="true" android:allowBackup="true"
android:icon="@drawable/ic_launcher" android:icon="@drawable/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
@@ -23,7 +24,7 @@
</activity> </activity>
<activity <activity
android:name="com.idlegandalf.ledd.SettingsActivity" android:name=".SettingsActivity"
android:label="" android:label=""
android:parentActivityName="com.idlegandalf.ledd.ColorActivity"> android:parentActivityName="com.idlegandalf.ledd.ColorActivity">
@@ -33,11 +34,7 @@
android:value="com.idlegandalf.ledd.ColorActivity" /> android:value="com.idlegandalf.ledd.ColorActivity" />
</activity> </activity>
<service android:name="com.idlegandalf.ledd.ColorService" /> <service android:name=".services.ColorService"/>
<activity
android:name="com.idlegandalf.ledd.AssistantActivity"
android:label="" />
</application> </application>
</manifest> </manifest>

View File

@@ -1,73 +0,0 @@
package com.idlegandalf.ledd;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.widget.FrameLayout;
import com.idlegandalf.ledd.fragments.WelcomeFragment;
import butterknife.Bind;
import butterknife.ButterKnife;
public class AssistantActivity extends AppCompatActivity {
@Bind(R.id.fragmentContainer)
FrameLayout container;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_asistent);
ButterKnife.bind(this);
// Check that the activity is using the layout version with
// the fragment_container FrameLayout
if (container != null) {
// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
if (savedInstanceState != null) {
return;
}
// Create a new Fragment to be placed in the activity layout
WelcomeFragment welcomeFragment = new WelcomeFragment();
// In case this activity was started with special instructions from an
// Intent, pass the Intent's extras to the fragment as arguments
welcomeFragment.setArguments(getIntent().getExtras());
// Add the fragment to the 'fragment_container' FrameLayout
getFragmentManager().beginTransaction()
.add(R.id.fragmentContainer, welcomeFragment).commit();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.welcome, menu);
return true;
}
public void switchFragment(Fragment fragment) {
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragmentContainer, fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
@Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() > 0) {
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
}

View File

@@ -1,37 +1,36 @@
package com.idlegandalf.ledd; package com.idlegandalf.ledd;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.widget.DrawerLayout; import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle; import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Gravity; import android.view.Gravity;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import com.idlegandalf.ledd.components.LEDDHelper;
import com.idlegandalf.ledd.components.RGBStripe; import com.idlegandalf.ledd.components.RGBStripe;
import com.idlegandalf.ledd.components.StripeGroup; import com.idlegandalf.ledd.components.StripeGroup;
import com.idlegandalf.ledd.utils.ColorPicker; import com.idlegandalf.ledd.helper.LedDHelper;
import butterknife.Bind; import butterknife.Bind;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import hugo.weaving.DebugLog;
public class ColorActivity extends AppCompatActivity { public class ColorActivity extends AppCompatActivity {
@Bind(R.id.colorPicker)
ColorPicker mWheel;
@Bind(R.id.drawer_layout) @Bind(R.id.drawer_layout)
DrawerLayout mDrawerLayout; DrawerLayout mDrawerLayout;
@Bind(R.id.toolbar)
Toolbar toolbar;
private ActionBarDrawerToggle mDrawerToggle; private ActionBarDrawerToggle mDrawerToggle;
private LEDDHelper mAPI; private LedDHelper mAPI;
private RGBStripe mActiveStripe; private RGBStripe mActiveStripe;
private StripeGroup mActiveGroup; private StripeGroup mActiveGroup;
private boolean firstRun = false; private boolean firstRun = false;
@@ -49,6 +48,9 @@ public class ColorActivity extends AppCompatActivity {
// TODO: Display error // TODO: Display error
} }
setSupportActionBar(toolbar);
toolbar.setTitle("LedD");
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.string.app_name, R.string.app_name) { mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.string.app_name, R.string.app_name) {
/** Called when a drawer has settled in a completely closed state. */ /** Called when a drawer has settled in a completely closed state. */
@@ -66,24 +68,9 @@ public class ColorActivity extends AppCompatActivity {
mDrawerLayout.setDrawerListener(mDrawerToggle); mDrawerLayout.setDrawerListener(mDrawerToggle);
// enable Homebutton navigation to drawer // enable Homebutton navigation to drawer
//getSupportActionBar().setDisplayHomeAsUpEnabled(true); if (getSupportActionBar() != null) {
//getSupportActionBar().setHomeButtonEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// getSupportActionBar().setIcon(R.drawable.ic_bar); getSupportActionBar().setHomeButtonEnabled(true);
if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean(
"firstRun", true)) {
System.out.println("first run!");
firstRun = true;
Intent intent = new Intent(this, AssistantActivity.class);
startActivity(intent);
}
if (ColorApplication.getInstance().isAPIActive()) {
this.mAPI = ColorApplication.getInstance().getAPI();
System.out.println("API active!");
} else {
System.out.println("API not active :(");
this.finish();
} }
} }
@@ -116,12 +103,6 @@ public class ColorActivity extends AppCompatActivity {
} }
// Handle your other action bar items... // Handle your other action bar items...
switch (item.getItemId()) {
case R.id.action_settings:
Intent intent = new Intent(this, SettingsActivity.class);
startActivity(intent);
return super.onOptionsItemSelected(item);
}
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
@@ -140,8 +121,17 @@ public class ColorActivity extends AppCompatActivity {
return super.onKeyDown(keyCode, event); return super.onKeyDown(keyCode, event);
} }
@DebugLog
@Override
protected void onPause() {
super.onPause();
ColorApplication.getInstance().teardown();
}
@DebugLog
@Override @Override
protected void onDestroy() { protected void onDestroy() {
super.onDestroy(); super.onDestroy();
ColorApplication.getInstance().teardown();
} }
} }

View File

@@ -3,14 +3,20 @@ package com.idlegandalf.ledd;
import android.app.Application; import android.app.Application;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import com.idlegandalf.ledd.components.LEDDHelper; import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.idlegandalf.ledd.components.Host;
import com.idlegandalf.ledd.helper.LedDHelper;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap;
import java.util.Set;
import hugo.weaving.DebugLog;
public class ColorApplication extends Application { public class ColorApplication extends Application {
private static ColorApplication singleton; private static ColorApplication singleton;
private LEDDHelper mAPI = null; private HashMap<Host, LedDHelper> ledDHelpers;
private boolean mAPIActive = false;
public static ColorApplication getInstance() { public static ColorApplication getInstance() {
return singleton; return singleton;
@@ -20,36 +26,43 @@ public class ColorApplication extends Application {
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
singleton = this; singleton = this;
try {
initAPI(); ledDHelpers = new HashMap<>();
} catch (IOException e) {
e.printStackTrace(); if (PreferenceManager.getDefaultSharedPreferences(this).contains("hosts")) {
Set<Host> hosts = new Gson().fromJson(PreferenceManager.getDefaultSharedPreferences(this).getString("hosts", ""), new
TypeToken<Set<Host>>() {
}.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());
}
public LedDHelper getHelperForHost(Host host) throws IOException {
System.out.println("host: " + host.toString());
if (ledDHelpers.containsKey(host)) {
return ledDHelpers.get(host);
} else {
LedDHelper dHelper = new LedDHelper(host, getApplicationContext());
ledDHelpers.put(host, dHelper);
return dHelper;
} }
} }
public LEDDHelper getAPI() { @DebugLog
return this.mAPI; public void teardown() {
} for (LedDHelper dHelper : ledDHelpers.values()) {
dHelper.teardown();
public void initAPI() throws IOException {
if (PreferenceManager.getDefaultSharedPreferences(this)
.contains("pref_key_host")) {
mAPI = new LEDDHelper(PreferenceManager
.getDefaultSharedPreferences(this).getString(
"pref_key_host", ""),
PreferenceManager
.getDefaultSharedPreferences(this).getInt(
"pref_key_port", 8825),
getApplicationContext()
);
this.mAPIActive = true;
System.out.println("api is declared as active now");
} }
}
public boolean isAPIActive() { PreferenceManager.getDefaultSharedPreferences(this).edit().putString("hosts", new Gson().toJson(ledDHelpers.keySet())).commit();
return mAPIActive;
} }
} }

View File

@@ -1,99 +0,0 @@
package com.idlegandalf.ledd;
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.widget.Toast;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
public class ColorService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
private DatagramSocket socket;
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
Bundle msgdata = msg.getData();
if (msgdata != null) {
try {
byte[] data = msgdata.getString("json").getBytes();
DatagramPacket packet = new DatagramPacket(data, data.length,
InetAddress.getByName(msgdata.getString("ip")), msgdata.getInt("port"));
socket.send(packet);
} catch (Exception e) {
e.printStackTrace();
}
}
// Stop the service using the startId, so that we don't stop
// the service in the middle of handling another job
//stopSelf(msg.arg1);
}
}
@Override
public void onCreate() {
Toast.makeText(this, "ColorService started", Toast.LENGTH_SHORT).show();
try {
socket = new DatagramSocket();
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Start up the thread running the service. Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block. We also make it
// background priority so CPU-intensive work will not disrupt our UI.
HandlerThread thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// For each start request, send a message to start a job and deliver the
// start ID so we know which request we're stopping when we finish the
// job
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.setData(intent.getExtras());
mServiceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
@Override
public void onDestroy() {
socket.close();
Toast.makeText(this, "ColorService stopped", Toast.LENGTH_SHORT).show();
}
}

View File

@@ -5,12 +5,26 @@ import android.support.v4.app.Fragment;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.LinearLayout;
import butterknife.Bind;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class DrawerFragment extends Fragment { public class DrawerFragment extends Fragment {
@Override @Bind(R.id.lay_add_host)
public View onCreateView(LayoutInflater inflater, ViewGroup container, LinearLayout addHost;
Bundle savedInstanceState) {
// Inflate the layout for this fragment @Override
return inflater.inflate(R.layout.drawer_fragment, container, false); 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
}
} }

View File

@@ -1,32 +0,0 @@
package com.idlegandalf.ledd;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
public abstract class ProgressBarActionBarActivity extends AppCompatActivity {
private ProgressBar mProgressBar;
public void setContentView(View view) {
init().addView(view);
}
public void setContentView(int layoutResID) {
getLayoutInflater().inflate(layoutResID, init(), true);
}
public void setContentView(View view, ViewGroup.LayoutParams params) {
init().addView(view, params);
}
private ViewGroup init() {
super.setContentView(R.layout.progress);
mProgressBar = (ProgressBar) findViewById(R.id.activity_bar);
return (ViewGroup) findViewById(R.id.activity_frame);
}
protected ProgressBar getProgressBar() {
return mProgressBar;
}
}

View File

@@ -8,10 +8,11 @@ public class SettingsActivity extends ActionBarActivity {
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
getSupportActionBar().setDisplayHomeAsUpEnabled(true); if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
// Display the fragment as the main content. // Display the fragment as the main content.
getFragmentManager().beginTransaction() getFragmentManager().beginTransaction().replace(android.R.id.content, new SettingsFragment()).commit();
.replace(android.R.id.content, new SettingsFragment())
.commit();
} }
} }

View File

@@ -0,0 +1,13 @@
package com.idlegandalf.ledd.callbacks;
public interface AddControllerCallback {
/**
* Returns when a controller was added successfully
*
* @param cid the new controller's id
*/
void onControllerAdded(int cid);
void onAddFailed(String msg, String detail);
}

View File

@@ -0,0 +1,9 @@
package com.idlegandalf.ledd.callbacks;
import com.idlegandalf.ledd.components.HSV;
public interface RecieveColorCallback {
void onColorRecieved(HSV color);
void onRecievFailed(String msg);
}

View File

@@ -0,0 +1,10 @@
package com.idlegandalf.ledd.components;
import org.json.JSONObject;
public abstract class AnswerTask implements Runnable {
public JSONObject response;
}

View File

@@ -9,5 +9,8 @@ import lombok.Setter;
@Getter @Getter
@Setter @Setter
public class Controller { public class Controller {
private int channels;
private String address;
private int i2c_device;
private ArrayList<RGBStripe> stripes; private ArrayList<RGBStripe> stripes;
} }

View File

@@ -6,7 +6,17 @@ import lombok.Setter;
@Getter @Getter
@Setter @Setter
public class HSV { public class HSV {
private float hue; private double hue;
private float saturation; private double saturation;
private float value; private double value;
public HSV(double h, double s, double v) {
this.hue = h;
this.saturation = s;
this.value = v;
}
public HSV() {
}
} }

View File

@@ -24,4 +24,22 @@ public class Host {
public String toString() { public String toString() {
return address + ":" + port; return address + ":" + port;
} }
@Override
public boolean equals(Object o) {
if (o instanceof Host) {
if (address.equals(((Host) o).address) && port == ((Host) o).port) return true;
}
return false;
}
@Override
public int hashCode() {
int result = 23;
result = 45 * result + port;
result = 45 * result + address.hashCode();
return result;
}
} }

View File

@@ -1,68 +0,0 @@
package com.idlegandalf.ledd.components;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import com.idlegandalf.ledd.ColorService;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
public class LEDDHelper {
private String mAddr;
private int mPort;
private Context context;
final String ACTION_SETCOLOR = "set_color";
final String ACTION_GETCOLOR = "get_color";
public LEDDHelper(String ip, int port, Context appl) throws UnsupportedEncodingException,
IOException {
this.mAddr = ip;
this.mPort = port;
this.context = appl;
}
/**
* Send RGB values to dameon using the stripeid
* @param sid Stripeid
* @param color Color in HSV format
* @throws JSONException not valid json
* @throws IOException socket error
*/
public void sendColor(int sid, HSV color)
throws JSONException, IOException {
JSONObject jnson = new JSONObject();
JSONArray hsv = new JSONArray();
hsv.put(color.getHue());
hsv.put(color.getSaturation());
hsv.put(color.getValue());
jnson.put("action", ACTION_SETCOLOR);
jnson.put("sid", sid);
jnson.put("color", hsv);
sendJSON(jnson.toString());
}
private void sendJSON(String json) throws IOException {
Intent intent = new Intent(context, ColorService.class);
Bundle bndl = new Bundle();
bndl.putString("json", json);
bndl.putString("host", this.mAddr);
bndl.putInt("port", mPort);
intent.putExtras(bndl);
context.startService(intent);
}
public void onDestroy() {
Intent intent = new Intent(context, ColorService.class);
context.stopService(intent);
}
}

View File

@@ -6,12 +6,12 @@ import lombok.Setter;
@Getter @Getter
@Setter @Setter
public class RGBStripe { public class RGBStripe {
private int id; private int id;
private int channelRed; private int channelRed;
private int channelGreen; private int channelGreen;
private int channelBlue; private int channelBlue;
private String nice_name; private String nice_name;
private HSV color; private HSV color;
private double gammaCorrection; private double gammaCorrection;
} }

View File

@@ -0,0 +1,35 @@
package com.idlegandalf.ledd.components;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.UUID;
import lombok.Getter;
@Getter
public class Sendable {
private Host recipient;
private JSONObject message;
private String ref;
private AnswerTask onAnswer;
public Sendable(JSONObject msg, AnswerTask task, Host host) throws JSONException {
this(msg, UUID.randomUUID().toString(), task, host);
}
public Sendable(JSONObject msg, String ref, AnswerTask task, Host recipient) throws JSONException {
this.message = msg;
this.ref = ref;
this.message.put("ref", ref);
this.onAnswer = task;
this.recipient = recipient;
}
public void onResponse(JSONObject object) {
if (onAnswer != null) {
onAnswer.response = object;
onAnswer.run();
}
}
}

View File

@@ -1,62 +1,64 @@
package com.idlegandalf.ledd.components; package com.idlegandalf.ledd.components;
import com.idlegandalf.ledd.helper.LedDHelper;
import org.json.JSONException; import org.json.JSONException;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
public class StripeGroup { public class StripeGroup {
private String mNiceName; private String mNiceName;
private String mDescription; private String mDescription;
private ArrayList<RGBStripe> mStripes; private ArrayList<RGBStripe> mStripes;
public String getNiceName() { public String getNiceName() {
return mNiceName; return mNiceName;
} }
public void setNiceName(String mNiceName) { public void setNiceName(String mNiceName) {
this.mNiceName = mNiceName; this.mNiceName = mNiceName;
} }
public String getDescription() { public String getDescription() {
return mDescription; return mDescription;
} }
public void setDescription(String mDescription) { public void setDescription(String mDescription) {
this.mDescription = mDescription; this.mDescription = mDescription;
} }
public RGBStripe getStripeByPos(int pos) { public RGBStripe getStripeByPos(int pos) {
return mStripes.get(pos); return mStripes.get(pos);
} }
public RGBStripe getStripeById(int sid) { public RGBStripe getStripeById(int sid) {
for (int i = 0; i < mStripes.size(); i++) { for (int i = 0; i < mStripes.size(); i++) {
if (mStripes.get(i).getId() == sid) { if (mStripes.get(i).getId() == sid) {
return mStripes.get(i); return mStripes.get(i);
} }
} }
return null; return null;
} }
public void setRGB(int r, int g, int b, LEDDHelper api) throws JSONException, IOException { public void setRGB(int r, int g, int b, LedDHelper api) throws JSONException, IOException {
for (int i = 0; i < mStripes.size(); i++) { for (int i = 0; i < mStripes.size(); i++) {
//mStripes.get(i).setRGB(r, g, b, api); //mStripes.get(i).setRGB(r, g, b, api);
} }
} }
public int addStripe(RGBStripe stripe) { public int addStripe(RGBStripe stripe) {
mStripes.add(stripe); mStripes.add(stripe);
return mStripes.size()-1; return mStripes.size() - 1;
} }
public void removeStripeByObject(RGBStripe stripe) { public void removeStripeByObject(RGBStripe stripe) {
for (int i = 0; i < mStripes.size(); i++) { for (int i = 0; i < mStripes.size(); i++) {
if (mStripes.get(i).getId() == stripe.getId()) { if (mStripes.get(i).getId() == stripe.getId()) {
mStripes.remove(i); mStripes.remove(i);
return; return;
} }
} }
} }
} }

View File

@@ -1,233 +0,0 @@
package com.idlegandalf.ledd.fragments;
import android.app.Fragment;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.idlegandalf.ledd.R;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import butterknife.Bind;
import butterknife.ButterKnife;
public class StepOneFragment extends Fragment {
@Bind(R.id.step2_back)
Button mBack;
@Bind(R.id.ipSelect)
EditText mAutoIP;
@Bind(R.id.step2_next)
Button mTest;
@Bind(R.id.portSelect)
EditText mAutoPort;
ArrayList<String> mIPList = new ArrayList<>();
boolean isAutoDetected = false;
public static StepOneFragment newInstance(String addrs) {
Bundle args = new Bundle();
args.putString("ips", addrs);
StepOneFragment fragment = new StepOneFragment();
fragment.setArguments(args);
return fragment;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_step1, container, false);
ButterKnife.bind(this, v);
return v;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
String ips = getArguments().getString("ips");
if (ips != null) {
if (!ips.isEmpty()) {
for (String string : ips.split(";")) {
if (string.isEmpty()) {
System.out.println("added addr " + string);
mIPList.add(string);
}
}
if (mIPList.size() > 0) isAutoDetected = true;
}
}
mBack.setOnClickListener(nextClickListener);
mTest.setOnClickListener(nextClickListener);
}
private OnClickListener nextClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.step2_back:
getActivity().onBackPressed();
break;
case R.id.step2_next:
System.out.println("forward calling!");
testController();
break;
default:
break;
}
}
};
private void testController() {
ConnectivityManager connManager = (ConnectivityManager) getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mWifi = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
if (mWifi.isConnected()) {
setInputState(false);
if (!isValidAddrInput(mAutoIP, mAutoPort)) {
setInputState(true);
return;
}
getActivity().setProgressBarIndeterminateVisibility(true);
getActivity().setProgressBarVisibility(true);
new pokeController().execute(mAutoIP.toString(), mAutoPort.toString());
} else {
Toast.makeText(getActivity().getApplicationContext(), "please connect WiFi", Toast.LENGTH_LONG).show();
}
}
private class pokeController extends AsyncTask<String, Void, Boolean> {
protected Boolean doInBackground(String... ippo) {
try {
InetAddress controller = InetAddress.getByName(ippo[0]);
int port = Integer.parseInt(ippo[1]);
DatagramSocket socket = new DatagramSocket();
String hstr = new JSONObject().put("action", 5).toString();
DatagramPacket hello = new DatagramPacket(hstr.getBytes(), hstr.getBytes().length);
hello.setPort(port);
socket.setSoTimeout(100);
if (!controller.isReachable(50)) {
socket.close();
return false;
}
hello.setAddress(controller);
socket.send(hello);
DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);
try {
socket.receive(packet);
} catch (SocketTimeoutException e) {
socket.close();
return false;
}
Toast.makeText(getActivity().getApplicationContext(), new String(packet.getData(), 0, packet.getLength()), Toast.LENGTH_LONG).show();
JSONObject resjson = new JSONObject(new String(packet.getData(), 0, packet.getLength()));
if (resjson.getInt("action") != 5) {
socket.close();
return false;
}
socket.close();
} catch (SocketException e1) {
return false;
} catch (IOException e1) {
return false;
} catch (JSONException e) {
return false;
}
return true;
}
protected void onProgressUpdate(Void... progress) {
}
protected void onPostExecute(Boolean result) {
getActivity().setProgressBarIndeterminateVisibility(false);
getActivity().setProgressBarVisibility(false);
setInputState(true);
if (result) {
Snackbar.make(getActivity().findViewById(R.id.linlayp), "found daemon running on " +
"address " + mAutoIP.toString() + ":" + mAutoPort.toString(), Snackbar.LENGTH_LONG).show();
} else {
Snackbar.make(getActivity().findViewById(R.id.linlayp), "No running daemon " + "found", Snackbar.LENGTH_LONG).show();
}
}
}
private boolean isValidIPFromEditText(EditText atv) {
String exip[] = atv.toString().trim().split("\\.");
if (exip.length != 4) return false;
for (String string : exip) {
if (!string.isEmpty()) {
try {
if (Integer.parseInt(string) < 0 || Integer.parseInt(string) > 255) return false;
} catch (NumberFormatException e) {
return false;
}
}
}
return true;
}
private boolean isValidPortFromEditText(EditText atv) {
return !atv.toString().isEmpty() && Integer.parseInt(atv.toString()) > 1023 && Integer.parseInt(atv.toString()) <= 65535;
}
private boolean isValidAddrInput(EditText ipatv, EditText portatv) {
if (!isValidIPFromEditText(ipatv)) {
Snackbar.make(getActivity().findViewById(R.id.linlayp), "Please enter valid IP " + "address", Snackbar.LENGTH_LONG).show();
return false;
}
if (!isValidPortFromEditText(portatv)) {
Snackbar.make(getActivity().findViewById(R.id.linlayp), "Please enter valid port " + "(1024-65535)", Snackbar.LENGTH_LONG).show();
return false;
}
return true;
}
private void setInputState(boolean state) {
mAutoIP.setEnabled(state);
mAutoPort.setEnabled(state);
mBack.setEnabled(state);
mTest.setEnabled(state);
}
}

View File

@@ -1,7 +0,0 @@
package com.idlegandalf.ledd.fragments;
import android.app.Fragment;
public class StepStripesFragment extends Fragment {
}

View File

@@ -1,218 +0,0 @@
package com.idlegandalf.ledd.fragments;
import android.app.Fragment;
import android.content.Context;
import android.net.nsd.NsdManager;
import android.net.nsd.NsdServiceInfo;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.idlegandalf.ledd.AssistantActivity;
import com.idlegandalf.ledd.R;
import com.idlegandalf.ledd.components.Host;
import java.net.Inet4Address;
import java.util.ArrayList;
import butterknife.Bind;
import butterknife.ButterKnife;
public class WelcomeFragment extends Fragment {
@Bind(R.id.step1_auto)
Button mAuto;
@Bind(R.id.step1_manual)
Button mManual;
@Bind(R.id.host_container)
LinearLayout hostContainer;
@Bind(R.id.toolbar)
Toolbar toolbar;
NsdManager mNsdManager;
final String TAG = "ColorD";
NsdManager.DiscoveryListener mDiscoveryListener;
NsdManager.ResolveListener mResolveListener;
ArrayList<Host> hosts;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_welcome, container, false);
ButterKnife.bind(this, v);
return v;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mAuto.setOnClickListener(nextClickListener);
mManual.setOnClickListener(nextClickListener);
((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);
hosts = new ArrayList<>();
mResolveListener = new NsdManager.ResolveListener() {
@Override
public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
// Called when the resolve fails. Use the error code to debug.
Log.e(TAG, "Resolve failed" + errorCode);
}
@Override
public void onServiceResolved(final NsdServiceInfo serviceInfo) {
Log.e(TAG, "Resolve Succeeded. " + serviceInfo);
if (serviceInfo.getHost() instanceof Inet4Address) {
Log.d(TAG, "Found IPv4! Yay!");
final Host fHost = new Host(serviceInfo.getHost().getHostAddress(), serviceInfo.getPort());
if (!hosts.contains(fHost)) {
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.welcome_host);
host.setText(serviceInfo.getHost().getHostAddress() + ":" + serviceInfo.getPort());
host.setTag(serviceInfo);
View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View v) {
StepOneFragment stepOneFragment = StepOneFragment.newInstance(hosts.get((int) v.getTag()).toString());
((AssistantActivity) getActivity()).switchFragment(stepOneFragment);
}
};
v.setOnClickListener(listener);
host.setOnClickListener(listener);
v.setTag(hosts.size());
host.setTag(hosts.size());
hostContainer.addView(v);
hosts.add(fHost);
}
});
}
}
}
};
mDiscoveryListener = new NsdManager.DiscoveryListener() {
// Called as soon as service discovery begins.
@Override
public void onDiscoveryStarted(String regType) {
Log.d(TAG, "Service discovery started");
}
@Override
public void onServiceFound(NsdServiceInfo service) {
// A service was found! Do something with it.
Log.d(TAG, "Service discovery success " + service);
if (!service.getServiceType().equals("_ledd._tcp.")) {
// Service type is the string containing the protocol and
// transport layer for this service.
Log.d(TAG, "Unknown Service Type: " + service.getServiceType());
} else {
mNsdManager.resolveService(service, mResolveListener);
}
}
@Override
public void onServiceLost(NsdServiceInfo service) {
// When the network service is no longer available.
// Internal bookkeeping code goes here.
Log.e(TAG, "service lost" + service);
}
@Override
public void onDiscoveryStopped(String serviceType) {
Log.i(TAG, "Discovery stopped: " + serviceType);
}
@Override
public void onStartDiscoveryFailed(String serviceType, int errorCode) {
Log.e(TAG, "Discovery failed: Error code:" + errorCode);
mNsdManager.stopServiceDiscovery(this);
}
@Override
public void onStopDiscoveryFailed(String serviceType, int errorCode) {
Log.e(TAG, "Discovery failed: Error code:" + errorCode);
mNsdManager.stopServiceDiscovery(this);
}
};
}
private View.OnClickListener nextClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.step1_auto:
System.out.println("auto pressed");
//getProgressBar().setIndeterminate(true);
//setProgressBarIndeterminateVisibility(true);
//setProgressBarVisibility(true);
//setProgressBarIndeterminate(true);
setButtonState(false);
mNsdManager = (NsdManager) getActivity().getSystemService(Context.NSD_SERVICE);
mNsdManager.discoverServices("_ledd._tcp", NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
break;
case R.id.step1_manual:
System.out.println("manual pressed");
setButtonState(false);
StepOneFragment stepOneFragment = StepOneFragment.newInstance(null);
((AssistantActivity) getActivity()).switchFragment(stepOneFragment);
setButtonState(true);
break;
default:
break;
}
}
};
void setButtonState(boolean state) {
mAuto.setEnabled(state);
mManual.setEnabled(state);
}
@Override
public void onPause() {
if (mNsdManager != null) {
tearDown();
setButtonState(true);
}
super.onPause();
}
@Override
public void onDestroy() {
if (mNsdManager != null) tearDown();
super.onDestroy();
}
// NsdHelper's tearDown method
public void tearDown() {
mNsdManager.stopServiceDiscovery(mDiscoveryListener);
}
}

View File

@@ -0,0 +1,155 @@
package com.idlegandalf.ledd.helper;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import com.idlegandalf.ledd.callbacks.AddControllerCallback;
import com.idlegandalf.ledd.callbacks.RecieveColorCallback;
import com.idlegandalf.ledd.components.AnswerTask;
import com.idlegandalf.ledd.components.HSV;
import com.idlegandalf.ledd.components.Host;
import com.idlegandalf.ledd.services.ColorService;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import hugo.weaving.DebugLog;
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;
private Context context;
private ColorService.ColorBinder binderService;
private boolean mBound = false;
ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
System.out.println("service bound!");
binderService = (ColorService.ColorBinder) service;
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
public LedDHelper(Host host, Context appl) throws IOException {
this.host = host;
this.context = appl;
Intent intent = new Intent(appl, ColorService.class);
appl.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
/**
* 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
* @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 {
JSONObject jnson = new JSONObject();
jnson.put("action", ACTION_ADDCONTROLLER);
jnson.put("channels", channels);
jnson.put("i2c_dev", i2c_dev);
jnson.put("address", address);
sendJSON(jnson, new AnswerTask() {
@Override
public void run() {
try {
if (response.getBoolean("success")) {
callback.onControllerAdded(response.getInt("cid"));
} else {
callback.onAddFailed(response.getString("message"), response.getString("message_detail"));
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Set color using the stripeid
*
* @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 {
JSONObject jnson = new JSONObject();
JSONObject hsv = new JSONObject();
hsv.put("h", color.getHue());
hsv.put("s", color.getSaturation());
hsv.put("v", color.getValue());
jnson.put("action", ACTION_SETCOLOR);
jnson.put("sid", sid);
jnson.put("color", hsv);
sendJSON(jnson, null);
}
/**
* Get color using the stripeid
*
* @param sid Stripeid
* @throws JSONException no valid json
* @throws IOException socket error
*/
public void getColor(int sid, final RecieveColorCallback callback) throws JSONException, IOException {
JSONObject jnson = new JSONObject();
jnson.put("action", ACTION_GETCOLOR);
jnson.put("sid", sid);
sendJSON(jnson, new AnswerTask() {
@Override
public void run() {
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")));
} else {
callback.onRecievFailed(response.getString("message"));
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
private void sendJSON(JSONObject json, AnswerTask task) throws IOException, JSONException {
if (mBound) binderService.queueSend(host, json, task);
}
@DebugLog
public void teardown() {
if (mBound) {
context.unbindService(mConnection);
mBound = false;
}
}
}

View File

@@ -0,0 +1,143 @@
package com.idlegandalf.ledd.services;
import android.app.Service;
import android.content.Intent;
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.Sendable;
import com.koushikdutta.async.AsyncServer;
import com.koushikdutta.async.AsyncSocket;
import com.koushikdutta.async.ByteBufferList;
import com.koushikdutta.async.DataEmitter;
import com.koushikdutta.async.Util;
import com.koushikdutta.async.callback.ConnectCallback;
import com.koushikdutta.async.callback.DataCallback;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.concurrent.LinkedBlockingQueue;
import hugo.weaving.DebugLog;
public class ColorService extends Service {
private final IBinder mBinder = new ColorBinder();
private LinkedBlockingQueue<Sendable> queue;
private Worker<Sendable> worker;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return -1;
}
@Override
public IBinder onBind(Intent intent) {
queue = new LinkedBlockingQueue<>();
worker = new Worker<>(queue);
new Thread(worker).start();
return mBinder;
}
@Override
public void onDestroy() {
worker.stop();
}
private static class Worker<T> implements Runnable {
private final LinkedBlockingQueue<T> workQueue;
private HashMap<Host, AsyncSocket> socketHashMap;
private HashMap<String, Sendable> sendableHashMap;
DataCallback dataCallback = new DataCallback() {
@Override
public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
JSONObject resp = null;
try {
resp = new JSONObject(new String(bb.getAllByteArray()));
} catch (JSONException e) {
e.printStackTrace();
}
if (resp != null) {
try {
if (sendableHashMap.containsKey(resp.getString("ref"))) {
sendableHashMap.get(resp.getString("ref")).onResponse(resp);
sendableHashMap.remove(resp.getString("ref"));
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
};
public Worker(LinkedBlockingQueue<T> workQueue) {
this.workQueue = workQueue;
this.socketHashMap = new HashMap<>();
this.sendableHashMap = new HashMap<>();
}
@Override
@DebugLog
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
final T item = workQueue.take();
if (item instanceof Sendable) {
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
("UTF-8"), null);
sendableHashMap.put(((Sendable) item).getRef(), (Sendable) item);
} else {
AsyncServer.getDefault().connectSocket(new InetSocketAddress(((Sendable) item).getRecipient().getAddress(), ((Sendable)
item).getRecipient().getPort()), new ConnectCallback() {
@Override
public void onConnectCompleted(Exception ex, final AsyncSocket socket) {
if (ex == null) {
socket.setDataCallback(dataCallback);
socketHashMap.put(((Sendable) item).getRecipient(), socket);
if (!workQueue.contains(item)) {
workQueue.add(item);
}
} else {
ex.printStackTrace();
}
}
});
}
}
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
break;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
public void stop() {
Thread.currentThread().interrupt();
}
}
public class ColorBinder extends Binder {
public String queueSend(Host 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();
}
}
}

View File

@@ -1,352 +0,0 @@
/*
* Copyright 2013 Piotr Adamus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.idlegandalf.ledd.utils;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ComposeShader;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Paint.Join;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.RadialGradient;
import android.graphics.RectF;
import android.graphics.Shader.TileMode;
import android.graphics.SweepGradient;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class ColorPicker extends View {
/**
* Customizable display parameters (in percents)
*/
private final int paramOuterPadding = 2; // outer padding of the whole color picker view
private final int paramInnerPadding = 5; // distance between value slider wheel and inner color wheel
private final int paramValueSliderWidth = 10; // width of the value slider
private final int paramArrowPointerSize = 4; // size of the arrow pointer; set to 0 to hide the pointer
private Paint colorWheelPaint;
private Paint valueSliderPaint;
private Paint colorViewPaint;
private Paint colorPointerPaint;
private RectF colorPointerCoords;
private Paint valuePointerPaint;
private Paint valuePointerArrowPaint;
private RectF outerWheelRect;
private RectF innerWheelRect;
private Path colorViewPath;
private Path valueSliderPath;
private Path arrowPointerPath;
private Bitmap colorWheelBitmap;
private int valueSliderWidth;
private int innerPadding;
private int outerPadding;
private int arrowPointerSize;
private int outerWheelRadius;
private int innerWheelRadius;
private int colorWheelRadius;
private Matrix gradientRotationMatrix;
/** Currently selected color */
private float[] colorHSV = new float[] { 0f, 0f, 1f };
public ColorPicker(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public ColorPicker(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ColorPicker(Context context) {
super(context);
init();
}
private void init() {
colorPointerPaint = new Paint();
colorPointerPaint.setStyle(Style.STROKE);
colorPointerPaint.setStrokeWidth(2f);
colorPointerPaint.setARGB(128, 0, 0, 0);
valuePointerPaint = new Paint();
valuePointerPaint.setStyle(Style.STROKE);
valuePointerPaint.setStrokeWidth(2f);
valuePointerArrowPaint = new Paint();
colorWheelPaint = new Paint();
colorWheelPaint.setAntiAlias(true);
colorWheelPaint.setDither(true);
valueSliderPaint = new Paint();
valueSliderPaint.setAntiAlias(true);
valueSliderPaint.setDither(true);
colorViewPaint = new Paint();
colorViewPaint.setAntiAlias(true);
colorViewPath = new Path();
valueSliderPath = new Path();
arrowPointerPath = new Path();
outerWheelRect = new RectF();
innerWheelRect = new RectF();
colorPointerCoords = new RectF();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int size = Math.min(widthSize, heightSize);
setMeasuredDimension(size, size);
}
@SuppressLint("DrawAllocation")
@Override
protected void onDraw(Canvas canvas) {
int centerX = getWidth() / 2;
int centerY = getHeight() / 2;
// drawing color wheel
canvas.drawBitmap(colorWheelBitmap, centerX - colorWheelRadius, centerY - colorWheelRadius, null);
// drawing color view
colorViewPaint.setColor(Color.HSVToColor(colorHSV));
canvas.drawPath(colorViewPath, colorViewPaint);
// drawing value slider
float[] hsv = new float[] { colorHSV[0], colorHSV[1], 1f };
SweepGradient sweepGradient = new SweepGradient(centerX, centerY, new int[] { Color.BLACK, Color.HSVToColor(hsv), Color.WHITE }, null);
sweepGradient.setLocalMatrix(gradientRotationMatrix);
valueSliderPaint.setShader(sweepGradient);
canvas.drawPath(valueSliderPath, valueSliderPaint);
// drawing color wheel pointer
float hueAngle = (float) Math.toRadians(colorHSV[0]);
int colorPointX = (int) (-Math.cos(hueAngle) * colorHSV[1] * colorWheelRadius) + centerX;
int colorPointY = (int) (-Math.sin(hueAngle) * colorHSV[1] * colorWheelRadius) + centerY;
float pointerRadius = 0.075f * colorWheelRadius;
int pointerX = (int) (colorPointX - pointerRadius / 2);
int pointerY = (int) (colorPointY - pointerRadius / 2);
colorPointerCoords.set(pointerX, pointerY, pointerX + pointerRadius, pointerY + pointerRadius);
canvas.drawOval(colorPointerCoords, colorPointerPaint);
// drawing value pointer
valuePointerPaint.setColor(Color.HSVToColor(new float[] { 0f, 0f, 1f - colorHSV[2] }));
double valueAngle = (colorHSV[2] - 0.5f) * Math.PI;
float valueAngleX = (float) Math.cos(valueAngle);
float valueAngleY = (float) Math.sin(valueAngle);
canvas.drawLine(valueAngleX * innerWheelRadius + centerX, valueAngleY * innerWheelRadius + centerY, valueAngleX * outerWheelRadius + centerX,
valueAngleY * outerWheelRadius + centerY, valuePointerPaint);
// drawing pointer arrow
if (arrowPointerSize > 0) {
drawPointerArrow(canvas);
}
}
private void drawPointerArrow(Canvas canvas) {
int centerX = getWidth() / 2;
int centerY = getHeight() / 2;
double tipAngle = (colorHSV[2] - 0.5f) * Math.PI;
double leftAngle = tipAngle + Math.PI / 96;
double rightAngle = tipAngle - Math.PI / 96;
double tipAngleX = Math.cos(tipAngle) * outerWheelRadius;
double tipAngleY = Math.sin(tipAngle) * outerWheelRadius;
double leftAngleX = Math.cos(leftAngle) * (outerWheelRadius + arrowPointerSize);
double leftAngleY = Math.sin(leftAngle) * (outerWheelRadius + arrowPointerSize);
double rightAngleX = Math.cos(rightAngle) * (outerWheelRadius + arrowPointerSize);
double rightAngleY = Math.sin(rightAngle) * (outerWheelRadius + arrowPointerSize);
arrowPointerPath.reset();
arrowPointerPath.moveTo((float) tipAngleX + centerX, (float) tipAngleY + centerY);
arrowPointerPath.lineTo((float) leftAngleX + centerX, (float) leftAngleY + centerY);
arrowPointerPath.lineTo((float) rightAngleX + centerX, (float) rightAngleY + centerY);
arrowPointerPath.lineTo((float) tipAngleX + centerX, (float) tipAngleY + centerY);
valuePointerArrowPaint.setColor(Color.HSVToColor(colorHSV));
valuePointerArrowPaint.setStyle(Style.FILL);
canvas.drawPath(arrowPointerPath, valuePointerArrowPaint);
valuePointerArrowPaint.setStyle(Style.STROKE);
valuePointerArrowPaint.setStrokeJoin(Join.ROUND);
valuePointerArrowPaint.setColor(Color.BLACK);
canvas.drawPath(arrowPointerPath, valuePointerArrowPaint);
}
@Override
protected void onSizeChanged(int width, int height, int oldw, int oldh) {
int centerX = width / 2;
int centerY = height / 2;
innerPadding = (int) (paramInnerPadding * width / 100);
outerPadding = (int) (paramOuterPadding * width / 100);
arrowPointerSize = (int) (paramArrowPointerSize * width / 100);
valueSliderWidth = (int) (paramValueSliderWidth * width / 100);
outerWheelRadius = width / 2 - outerPadding - arrowPointerSize;
innerWheelRadius = outerWheelRadius - valueSliderWidth;
colorWheelRadius = innerWheelRadius - innerPadding;
outerWheelRect.set(centerX - outerWheelRadius, centerY - outerWheelRadius, centerX + outerWheelRadius, centerY + outerWheelRadius);
innerWheelRect.set(centerX - innerWheelRadius, centerY - innerWheelRadius, centerX + innerWheelRadius, centerY + innerWheelRadius);
colorWheelBitmap = createColorWheelBitmap(colorWheelRadius * 2, colorWheelRadius * 2);
gradientRotationMatrix = new Matrix();
gradientRotationMatrix.preRotate(270, width / 2, height / 2);
colorViewPath.arcTo(outerWheelRect, 270, -180);
colorViewPath.arcTo(innerWheelRect, 90, 180);
valueSliderPath.arcTo(outerWheelRect, 270, 180);
valueSliderPath.arcTo(innerWheelRect, 90, -180);
}
private Bitmap createColorWheelBitmap(int width, int height) {
Bitmap bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
int colorCount = 12;
int colorAngleStep = 360 / 12;
int colors[] = new int[colorCount + 1];
float hsv[] = new float[] { 0f, 1f, 1f };
for (int i = 0; i < colors.length; i++) {
hsv[0] = (i * colorAngleStep + 180) % 360;
colors[i] = Color.HSVToColor(hsv);
}
colors[colorCount] = colors[0];
SweepGradient sweepGradient = new SweepGradient(width / 2, height / 2, colors, null);
RadialGradient radialGradient = new RadialGradient(width / 2, height / 2, colorWheelRadius, 0xFFFFFFFF, 0x00FFFFFF, TileMode.CLAMP);
ComposeShader composeShader = new ComposeShader(sweepGradient, radialGradient, PorterDuff.Mode.SRC_OVER);
colorWheelPaint.setShader(composeShader);
Canvas canvas = new Canvas(bitmap);
canvas.drawCircle(width / 2, height / 2, colorWheelRadius, colorWheelPaint);
return bitmap;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
int x = (int) event.getX();
int y = (int) event.getY();
int cx = x - getWidth() / 2;
int cy = y - getHeight() / 2;
double d = Math.sqrt(cx * cx + cy * cy);
if (d <= colorWheelRadius) {
colorHSV[0] = (float) (Math.toDegrees(Math.atan2(cy, cx)) + 180f);
colorHSV[1] = Math.max(0f, Math.min(1f, (float) (d / colorWheelRadius)));
invalidate();
} else if (x >= getWidth() / 2 && d >= innerWheelRadius) {
colorHSV[2] = (float) Math.max(0, Math.min(1, Math.atan2(cy, cx) / Math.PI + 0.5f));
invalidate();
}
return true;
}
return super.onTouchEvent(event);
}
public void setColor(int color) {
Color.colorToHSV(color, colorHSV);
}
public int getColor() {
return Color.HSVToColor(colorHSV);
}
@Override
protected Parcelable onSaveInstanceState() {
Bundle state = new Bundle();
state.putFloatArray("color", colorHSV);
state.putParcelable("super", super.onSaveInstanceState());
return state;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (state instanceof Bundle) {
Bundle bundle = (Bundle) state;
colorHSV = bundle.getFloatArray("color");
super.onRestoreInstanceState(bundle.getParcelable("super"));
} else {
super.onRestoreInstanceState(state);
}
}
}

View File

@@ -1,54 +0,0 @@
package com.idlegandalf.ledd.utils;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;
public class ColorPickerDialog extends AlertDialog {
private ColorPicker colorPickerView;
private final OnColorSelectedListener onColorSelectedListener;
public ColorPickerDialog(Context context, int initialColor, OnColorSelectedListener onColorSelectedListener) {
super(context);
this.onColorSelectedListener = onColorSelectedListener;
RelativeLayout relativeLayout = new RelativeLayout(context);
LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
colorPickerView = new ColorPicker(context);
colorPickerView.setColor(initialColor);
relativeLayout.addView(colorPickerView, layoutParams);
setButton(BUTTON_POSITIVE, context.getString(android.R.string.ok), onClickListener);
setButton(BUTTON_NEGATIVE, context.getString(android.R.string.cancel), onClickListener);
setView(relativeLayout);
}
private OnClickListener onClickListener = new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case BUTTON_POSITIVE:
int selectedColor = colorPickerView.getColor();
onColorSelectedListener.onColorSelected(selectedColor);
break;
case BUTTON_NEGATIVE:
dialog.dismiss();
break;
}
}
};
public interface OnColorSelectedListener {
public void onColorSelected(int color);
}
}

View File

@@ -1,73 +0,0 @@
package com.idlegandalf.ledd.utils;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.preference.DialogPreference;
import android.util.AttributeSet;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;
public class ColorPickerPreference extends DialogPreference {
public static final int DEFAULT_COLOR = Color.WHITE;
private int selectedColor;
private ColorPicker colorPickerView;
public ColorPickerPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected View onCreateDialogView() {
RelativeLayout relativeLayout = new RelativeLayout(getContext());
LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
colorPickerView = new ColorPicker(getContext());
colorPickerView.setId(1);
relativeLayout.addView(colorPickerView, layoutParams);
return relativeLayout;
}
@Override
protected void onBindDialogView(View view) {
super.onBindDialogView(view);
colorPickerView.setColor(selectedColor);
}
@Override
protected void onPrepareDialogBuilder(Builder builder) {
super.onPrepareDialogBuilder(builder);
builder.setTitle(null); // remove dialog title to get more space for color picker
}
@Override
protected void onDialogClosed(boolean positiveResult) {
if (positiveResult && shouldPersist()) {
if (callChangeListener(colorPickerView.getColor())) {
selectedColor = colorPickerView.getColor();
persistInt(selectedColor);
}
}
}
@Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
selectedColor = restoreValue ? getPersistedInt(DEFAULT_COLOR) : (Integer) defaultValue;
}
@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return a.getInt(index, DEFAULT_COLOR);
}
}

View File

@@ -1,401 +0,0 @@
/*
* Copyright 2013 Piotr Adamus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.idlegandalf.ledd.utils;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ComposeShader;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Paint.Join;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.RadialGradient;
import android.graphics.RectF;
import android.graphics.Shader.TileMode;
import android.graphics.SweepGradient;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class MultiColorPicker extends View {
/**
* Customizable display parameters (in percents)
*/
private final int paramOuterPadding = 2; // outer padding of the whole color picker view
private final int paramInnerPadding = 5; // distance between value slider wheel and inner color wheel
private final int paramValueSliderWidth = 10; // width of the value slider
private final int paramArrowPointerSize = 4; // size of the arrow pointer; set to 0 to hide the pointer
private final int paramColorCount = 5;
private final float paramHueSpreadAngle = 30f; // in degrees
private Paint colorWheelPaint;
private Paint valueSliderPaint;
private Paint colorViewPaint;
private Paint colorPointerPaint;
private RectF colorPointerCoords;
private Paint valuePointerPaint;
private Paint valuePointerArrowPaint;
private RectF outerWheelRect;
private RectF innerWheelRect;
private Path colorViewPath;
private Path valueSliderPath;
private Path arrowPointerPath;
private Bitmap colorWheelBitmap;
private int valueSliderWidth;
private int innerPadding;
private int outerPadding;
private int arrowPointerSize;
private int outerWheelRadius;
private int innerWheelRadius;
private int colorWheelRadius;
private Matrix gradientRotationMatrix;
/** Currently selected color */
private float[] colorHSV = new float[] { 0f, 0f, 1f };
private float[] adjacentHue = new float[paramColorCount];
public MultiColorPicker(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public MultiColorPicker(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MultiColorPicker(Context context) {
super(context);
init();
}
private void init() {
colorPointerPaint = new Paint();
colorPointerPaint.setStyle(Style.STROKE);
colorPointerPaint.setStrokeWidth(2f);
colorPointerPaint.setARGB(128, 0, 0, 0);
valuePointerPaint = new Paint();
valuePointerPaint.setStyle(Style.STROKE);
valuePointerPaint.setStrokeWidth(2f);
valuePointerArrowPaint = new Paint();
colorWheelPaint = new Paint();
colorWheelPaint.setAntiAlias(true);
colorWheelPaint.setDither(true);
valueSliderPaint = new Paint();
valueSliderPaint.setAntiAlias(true);
valueSliderPaint.setDither(true);
colorViewPaint = new Paint();
colorViewPaint.setAntiAlias(true);
colorViewPath = new Path();
valueSliderPath = new Path();
arrowPointerPath = new Path();
outerWheelRect = new RectF();
innerWheelRect = new RectF();
colorPointerCoords = new RectF();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int size = Math.min(widthSize, heightSize);
setMeasuredDimension(size, size);
}
@SuppressLint("DrawAllocation")
@Override
protected void onDraw(Canvas canvas) {
int centerX = getWidth() / 2;
int centerY = getHeight() / 2;
// drawing color wheel
canvas.drawBitmap(colorWheelBitmap, centerX - colorWheelRadius, centerY - colorWheelRadius, null);
// drawing color view
int[] segmentColors = getColors();
float sweepAngleStep = 180f / paramColorCount;
for (int i = 0; i < paramColorCount; i++) {
colorViewPath.reset();
colorViewPath.arcTo(outerWheelRect, 270 - i * sweepAngleStep, -sweepAngleStep);
colorViewPath.arcTo(innerWheelRect, 90 + (paramColorCount - i - 1) * sweepAngleStep, sweepAngleStep);
colorViewPaint.setColor(segmentColors[i]);
canvas.drawPath(colorViewPath, colorViewPaint);
}
// drawing value slider
float[] hsv = new float[] { colorHSV[0], colorHSV[1], 1f };
SweepGradient sweepGradient = new SweepGradient(centerX, centerY, new int[] { Color.BLACK, Color.HSVToColor(hsv), Color.WHITE }, null);
sweepGradient.setLocalMatrix(gradientRotationMatrix);
valueSliderPaint.setShader(sweepGradient);
canvas.drawPath(valueSliderPath, valueSliderPaint);
// drawing color wheel pointer
for (int i = 0; i < paramColorCount; i++) {
drawColorWheelPointer(canvas, (float) Math.toRadians(adjacentHue[i]));
}
// drawing value pointer
valuePointerPaint.setColor(Color.HSVToColor(new float[] { 0f, 0f, 1f - colorHSV[2] }));
double valueAngle = (colorHSV[2] - 0.5f) * Math.PI;
float valueAngleX = (float) Math.cos(valueAngle);
float valueAngleY = (float) Math.sin(valueAngle);
canvas.drawLine(valueAngleX * innerWheelRadius + centerX, valueAngleY * innerWheelRadius + centerY, valueAngleX * outerWheelRadius + centerX,
valueAngleY * outerWheelRadius + centerY, valuePointerPaint);
// drawing pointer arrow
if (arrowPointerSize > 0) {
drawPointerArrow(canvas);
}
}
private void drawColorWheelPointer(Canvas canvas, float hueAngle) {
int centerX = getWidth() / 2;
int centerY = getHeight() / 2;
int colorPointX = (int) (-Math.cos(hueAngle) * colorHSV[1] * colorWheelRadius) + centerX;
int colorPointY = (int) (-Math.sin(hueAngle) * colorHSV[1] * colorWheelRadius) + centerY;
float pointerRadius = 0.075f * colorWheelRadius;
int pointerX = (int) (colorPointX - pointerRadius / 2);
int pointerY = (int) (colorPointY - pointerRadius / 2);
colorPointerCoords.set(pointerX, pointerY, pointerX + pointerRadius, pointerY + pointerRadius);
canvas.drawOval(colorPointerCoords, colorPointerPaint);
}
private void drawPointerArrow(Canvas canvas) {
int centerX = getWidth() / 2;
int centerY = getHeight() / 2;
double tipAngle = (colorHSV[2] - 0.5f) * Math.PI;
double leftAngle = tipAngle + Math.PI / 96;
double rightAngle = tipAngle - Math.PI / 96;
double tipAngleX = Math.cos(tipAngle) * outerWheelRadius;
double tipAngleY = Math.sin(tipAngle) * outerWheelRadius;
double leftAngleX = Math.cos(leftAngle) * (outerWheelRadius + arrowPointerSize);
double leftAngleY = Math.sin(leftAngle) * (outerWheelRadius + arrowPointerSize);
double rightAngleX = Math.cos(rightAngle) * (outerWheelRadius + arrowPointerSize);
double rightAngleY = Math.sin(rightAngle) * (outerWheelRadius + arrowPointerSize);
arrowPointerPath.reset();
arrowPointerPath.moveTo((float) tipAngleX + centerX, (float) tipAngleY + centerY);
arrowPointerPath.lineTo((float) leftAngleX + centerX, (float) leftAngleY + centerY);
arrowPointerPath.lineTo((float) rightAngleX + centerX, (float) rightAngleY + centerY);
arrowPointerPath.lineTo((float) tipAngleX + centerX, (float) tipAngleY + centerY);
valuePointerArrowPaint.setColor(Color.HSVToColor(colorHSV));
valuePointerArrowPaint.setStyle(Style.FILL);
canvas.drawPath(arrowPointerPath, valuePointerArrowPaint);
valuePointerArrowPaint.setStyle(Style.STROKE);
valuePointerArrowPaint.setStrokeJoin(Join.ROUND);
valuePointerArrowPaint.setColor(Color.BLACK);
canvas.drawPath(arrowPointerPath, valuePointerArrowPaint);
}
@Override
protected void onSizeChanged(int width, int height, int oldw, int oldh) {
int centerX = width / 2;
int centerY = height / 2;
innerPadding = (int) (paramInnerPadding * width / 100);
outerPadding = (int) (paramOuterPadding * width / 100);
arrowPointerSize = (int) (paramArrowPointerSize * width / 100);
valueSliderWidth = (int) (paramValueSliderWidth * width / 100);
outerWheelRadius = width / 2 - outerPadding - arrowPointerSize;
innerWheelRadius = outerWheelRadius - valueSliderWidth;
colorWheelRadius = innerWheelRadius - innerPadding;
outerWheelRect.set(centerX - outerWheelRadius, centerY - outerWheelRadius, centerX + outerWheelRadius, centerY + outerWheelRadius);
innerWheelRect.set(centerX - innerWheelRadius, centerY - innerWheelRadius, centerX + innerWheelRadius, centerY + innerWheelRadius);
colorWheelBitmap = createColorWheelBitmap(colorWheelRadius * 2, colorWheelRadius * 2);
gradientRotationMatrix = new Matrix();
gradientRotationMatrix.preRotate(270, width / 2, height / 2);
valueSliderPath.arcTo(outerWheelRect, 270, 180);
valueSliderPath.arcTo(innerWheelRect, 90, -180);
}
private Bitmap createColorWheelBitmap(int width, int height) {
Bitmap bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
int colorCount = 12;
int colorAngleStep = 360 / 12;
int colors[] = new int[colorCount + 1];
float hsv[] = new float[] { 0f, 1f, 1f };
for (int i = 0; i < colors.length; i++) {
hsv[0] = (i * colorAngleStep + 180) % 360;
colors[i] = Color.HSVToColor(hsv);
}
colors[colorCount] = colors[0];
SweepGradient sweepGradient = new SweepGradient(width / 2, height / 2, colors, null);
RadialGradient radialGradient = new RadialGradient(width / 2, height / 2, colorWheelRadius, 0xFFFFFFFF, 0x00FFFFFF, TileMode.CLAMP);
ComposeShader composeShader = new ComposeShader(sweepGradient, radialGradient, PorterDuff.Mode.SRC_OVER);
colorWheelPaint.setShader(composeShader);
Canvas canvas = new Canvas(bitmap);
canvas.drawCircle(width / 2, height / 2, colorWheelRadius, colorWheelPaint);
return bitmap;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
int x = (int) event.getX();
int y = (int) event.getY();
int cx = x - getWidth() / 2;
int cy = y - getHeight() / 2;
double d = Math.sqrt(cx * cx + cy * cy);
if (d <= colorWheelRadius) {
colorHSV[0] = (float) (Math.toDegrees(Math.atan2(cy, cx)) + 180f);
colorHSV[1] = Math.max(0f, Math.min(1f, (float) (d / colorWheelRadius)));
updateAdjacentHue();
invalidate();
} else if (x >= getWidth() / 2 && d >= innerWheelRadius) {
colorHSV[2] = (float) Math.max(0, Math.min(1, Math.atan2(cy, cx) / Math.PI + 0.5f));
updateAdjacentHue();
invalidate();
}
return true;
}
return super.onTouchEvent(event);
}
private void updateAdjacentHue() {
for (int i = 0; i < paramColorCount; i++) {
adjacentHue[i] = (colorHSV[0] - paramHueSpreadAngle * (paramColorCount / 2 - i)) % 360.0f;
adjacentHue[i] = (adjacentHue[i] < 0) ? adjacentHue[i] + 360f : adjacentHue[i];
}
adjacentHue[paramColorCount / 2] = colorHSV[0];
}
public void setColor(int color) {
Color.colorToHSV(color, colorHSV);
updateAdjacentHue();
}
public int getColor() {
return Color.HSVToColor(colorHSV);
}
public int[] getColors() {
int[] colors = new int[paramColorCount];
float[] hsv = new float[3];
for (int i = 0; i < paramColorCount; i++) {
hsv[0] = adjacentHue[i];
hsv[1] = colorHSV[1];
hsv[2] = colorHSV[2];
colors[i] = Color.HSVToColor(hsv);
}
return colors;
}
@Override
protected Parcelable onSaveInstanceState() {
Bundle state = new Bundle();
state.putFloatArray("color", colorHSV);
state.putParcelable("super", super.onSaveInstanceState());
return state;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (state instanceof Bundle) {
Bundle bundle = (Bundle) state;
colorHSV = bundle.getFloatArray("color");
updateAdjacentHue();
super.onRestoreInstanceState(bundle.getParcelable("super"));
} else {
super.onRestoreInstanceState(state);
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 161 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 B

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid android:color="#000000" />
</shape>

View File

@@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingLeft="8dp"
android:paddingRight="8dp" >
<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:drawSelectorOnTop="false" />
</LinearLayout>

View File

@@ -1,21 +0,0 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<com.chiralcode.colorpicker.MultiColorPicker
android:id="@+id/multiColorPicker"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_gravity="center"
android:layout_weight="0.8" />
<Button
android:id="@+id/button"
android:layout_width="100dp"
android:layout_height="0dp"
android:layout_gravity="center_horizontal"
android:layout_weight="0.2"
android:text="@string/button_label" />
</LinearLayout>

View File

@@ -1,21 +0,0 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<com.chiralcode.colorpicker.ColorPicker
android:id="@+id/colorPicker"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_gravity="center"
android:layout_weight="0.8" />
<Button
android:id="@+id/button"
android:layout_width="100dp"
android:layout_height="0dp"
android:layout_gravity="center_horizontal"
android:layout_weight="0.2"
android:text="@string/button_label" />
</LinearLayout>

View File

@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:key="example_preferences" >
<com.chiralcode.colorpicker.ColorPickerPreference
android:defaultValue="0xffffffff"
android:key="color"
android:title="@string/pref_name"
android:summary="@string/pref_summary" />
</PreferenceScreen>

View File

@@ -1,25 +1,40 @@
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" <android.support.v4.widget.DrawerLayout
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout" android:id="@+id/drawer_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<!-- The main content view --> <!-- The main content view -->
<com.idlegandalf.ledd.utils.ColorPicker <LinearLayout
android:id="@+id/colorPicker" android:layout_width="fill_parent"
android:layout_width="wrap_content" android:layout_height="fill_parent"
android:layout_height="wrap_content" android:orientation="vertical">
/>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:minHeight="?android:attr/actionBarSize"/>
<FrameLayout
android:id="@+id/stripe_container"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
</LinearLayout>
<!-- The navigation drawer --> <!-- The navigation drawer -->
<fragment <fragment
android:name="com.idlegandalf.ledd.DrawerFragment"
android:id="@+id/drawer" android:id="@+id/drawer"
android:name="com.idlegandalf.ledd.DrawerFragment"
android:layout_width="240dp" android:layout_width="240dp"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_gravity="start" android:layout_gravity="start"
tools:layout="@layout/drawer_fragment" /> tools:layout="@layout/drawer_fragment"/>
</android.support.v4.widget.DrawerLayout> </android.support.v4.widget.DrawerLayout>

View File

@@ -1,8 +1,79 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@android:color/white" android:background="@android:color/white">
android:orientation="vertical" >
</LinearLayout> <LinearLayout
android:id="@+id/lay_settings"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:orientation="horizontal"
android:paddingBottom="5dp"
android:paddingLeft="5dp"
android:paddingTop="5dp">
<ImageView
android:layout_width="@dimen/nd_icon"
android:layout_height="@dimen/nd_icon"
android:layout_marginLeft="@dimen/space_before_icon"
android:src="@drawable/ic_tune_black_48dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"
android:text="Settings"
android:textAppearance="@style/TextAppearance.AppCompat.Button"/>
</LinearLayout>
<LinearLayout
android:id="@+id/lay_add_host"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_above="@id/lay_settings"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:orientation="horizontal"
android:paddingBottom="5dp"
android:paddingLeft="5dp"
android:paddingTop="5dp">
<ImageView
android:layout_width="@dimen/nd_icon"
android:layout_height="@dimen/nd_icon"
android:layout_marginLeft="@dimen/space_before_icon"
android:src="@drawable/ic_add_box_black_48dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"
android:text="Add Host"
android:textAppearance="@style/TextAppearance.AppCompat.Button"/>
</LinearLayout>
<LinearLayout
android:id="@+id/listview_controller_lay"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_above="@id/lay_add_host">
<ExpandableListView
android:id="@+id/listview_controller"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
</RelativeLayout>

View File

@@ -1,84 +0,0 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/linlayp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".StepOneActivity">
<TextView
android:id="@+id/text_welcome_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp"
android:text="Step 1.1: Select Controller manually"
android:textAppearance="?android:attr/textAppearanceLarge" />
<Button
android:id="@+id/step2_next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:text="test controller" />
<Button
android:id="@+id/step2_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:text="back" />
<LinearLayout
android:id="@+id/linBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/text_welcome_title"
android:layout_centerHorizontal="true"
android:layout_marginTop="50dp"
android:orientation="horizontal">
<android.support.design.widget.TextInputLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<EditText
android:id="@+id/ipSelect"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|left"
android:ems="8"
android:gravity="center_horizontal"
android:hint="IP address"
android:imeOptions="actionNext"
android:inputType="phone"
android:maxLength="15" />
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<EditText
android:id="@+id/portSelect"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:ems="4"
android:gravity="center_horizontal"
android:hint="port"
android:imeActionLabel="Test"
android:inputType="phone"
android:maxLength="5" />
</android.support.design.widget.TextInputLayout>
</LinearLayout>
</RelativeLayout>

View File

@@ -1,93 +0,0 @@
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin">
<TextView
android:id="@+id/text_welcome_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp"
android:text="Welcome"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textStyle="bold"/>
<TextView
android:id="@+id/welcome_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/text_welcome_title"
android:layout_centerHorizontal="true"
android:layout_marginTop="30dp"
android:text="Welcome to the RGB Stripe Control App. This assistent gives you an step-by-step introduction to setup your stripe configuration."
android:textAppearance="?android:attr/textAppearanceMedium"/>
<Button
android:id="@+id/step1_auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:text="autosearch"/>
<Button
android:id="@+id/step1_manual"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:text="set manual"/>
<TextView
android:id="@+id/text_choose"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/step1_auto"
android:layout_centerHorizontal="true"
android:layout_marginBottom="18dp"
android:text="choose way to select contoller"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textStyle="bold"/>
<ScrollView
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:layout_above="@id/text_choose"
android:layout_below="@id/welcome_text"
android:layout_marginBottom="20dp"
android:layout_marginTop="20dp">
<LinearLayout
android:id="@+id/host_container"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"/>
</ScrollView>
</RelativeLayout>
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlways"/>
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>

View File

@@ -1,10 +1,5 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android" <menu
xmlns:com.gh.stripecontrol="http://schemas.android.com/apk/res-auto" > >
<item
android:id="@+id/action_settings"
com.gh.stripecontrol:showAsAction="always"
android:title=""
android:icon="@drawable/ic_action_settings" />
</menu> </menu>

View File

@@ -1,4 +0,0 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
</menu>

View File

@@ -1,3 +0,0 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
</menu>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="primaryColor">#3ae765</color>
<color name="primaryColorDark">#69cc59</color>
</resources>

View File

@@ -3,5 +3,7 @@
<!-- Default screen margins, per the Android Design guidelines. --> <!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen> <dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen> <dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="nd_icon">30dp</dimen>
<dimen name="space_before_icon">7dp</dimen>
</resources> </resources>

View File

@@ -15,6 +15,11 @@
<!-- Application theme. --> <!-- Application theme. -->
<style name="AppTheme" parent="AppBaseTheme"> <style name="AppTheme" parent="AppBaseTheme">
<!-- All customizations that are NOT specific to a particular API-level can go here. --> <!-- All customizations that are NOT specific to a particular API-level can go here. -->
<!-- ...and here we setting appcompats color theming attrs -->
<item name="colorPrimary">@color/primaryColor</item>
<item name="colorPrimaryDark">@color/primaryColorDark</item>
</style> </style>
</resources> </resources>