Initial commit from non tracked working directory
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
147
app/src/main/java/com/idlegandalf/ledd/ColorActivity.java
Normal file
147
app/src/main/java/com/idlegandalf/ledd/ColorActivity.java
Normal file
@@ -0,0 +1,147 @@
|
||||
package com.idlegandalf.ledd;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v4.widget.DrawerLayout;
|
||||
import android.support.v7.app.ActionBarDrawerToggle;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.view.Gravity;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
||||
import com.idlegandalf.ledd.components.LEDDHelper;
|
||||
import com.idlegandalf.ledd.components.RGBStripe;
|
||||
import com.idlegandalf.ledd.components.StripeGroup;
|
||||
import com.idlegandalf.ledd.utils.ColorPicker;
|
||||
|
||||
import butterknife.Bind;
|
||||
import butterknife.ButterKnife;
|
||||
|
||||
public class ColorActivity extends AppCompatActivity {
|
||||
|
||||
@Bind(R.id.colorPicker)
|
||||
ColorPicker mWheel;
|
||||
@Bind(R.id.drawer_layout)
|
||||
DrawerLayout mDrawerLayout;
|
||||
private ActionBarDrawerToggle mDrawerToggle;
|
||||
private LEDDHelper mAPI;
|
||||
private RGBStripe mActiveStripe;
|
||||
private StripeGroup mActiveGroup;
|
||||
private boolean firstRun = false;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_color);
|
||||
ButterKnife.bind(this);
|
||||
|
||||
// check for connectivity
|
||||
ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
|
||||
if (networkInfo == null || !networkInfo.isConnected()) {
|
||||
// TODO: Display error
|
||||
}
|
||||
|
||||
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.string.app_name, R.string.app_name) {
|
||||
|
||||
/** Called when a drawer has settled in a completely closed state. */
|
||||
public void onDrawerClosed(View view) {
|
||||
// TODO: do things that have to be done here
|
||||
}
|
||||
|
||||
/** Called when a drawer has settled in a completely open state. */
|
||||
public void onDrawerOpened(View drawerView) {
|
||||
// TODO: do things that have to be done here
|
||||
}
|
||||
};
|
||||
|
||||
// set the drawer toggle as the DrawerListener
|
||||
mDrawerLayout.setDrawerListener(mDrawerToggle);
|
||||
|
||||
// enable Homebutton navigation to drawer
|
||||
//getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
//getSupportActionBar().setHomeButtonEnabled(true);
|
||||
// getSupportActionBar().setIcon(R.drawable.ic_bar);
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostCreate(Bundle savedInstanceState) {
|
||||
super.onPostCreate(savedInstanceState);
|
||||
// Sync the toggle state after onRestoreInstanceState has occurred.
|
||||
mDrawerToggle.syncState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
mDrawerToggle.onConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
// Pass the event to ActionBarDrawerToggle, if it returns
|
||||
// true, then it has handled the app icon touch event
|
||||
if (mDrawerToggle.onOptionsItemSelected(item)) {
|
||||
return true;
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_MENU) {
|
||||
if (mDrawerLayout.isDrawerOpen(Gravity.LEFT)) {
|
||||
mDrawerLayout.closeDrawer(Gravity.LEFT);
|
||||
} else {
|
||||
mDrawerLayout.openDrawer(Gravity.LEFT);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
}
|
||||
}
|
55
app/src/main/java/com/idlegandalf/ledd/ColorApplication.java
Normal file
55
app/src/main/java/com/idlegandalf/ledd/ColorApplication.java
Normal file
@@ -0,0 +1,55 @@
|
||||
package com.idlegandalf.ledd;
|
||||
|
||||
import android.app.Application;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
import com.idlegandalf.ledd.components.LEDDHelper;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class ColorApplication extends Application {
|
||||
private static ColorApplication singleton;
|
||||
private LEDDHelper mAPI = null;
|
||||
private boolean mAPIActive = false;
|
||||
|
||||
public static ColorApplication getInstance() {
|
||||
return singleton;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
singleton = this;
|
||||
try {
|
||||
initAPI();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public LEDDHelper getAPI() {
|
||||
return this.mAPI;
|
||||
}
|
||||
|
||||
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() {
|
||||
return mAPIActive;
|
||||
}
|
||||
}
|
99
app/src/main/java/com/idlegandalf/ledd/ColorService.java
Normal file
99
app/src/main/java/com/idlegandalf/ledd/ColorService.java
Normal file
@@ -0,0 +1,99 @@
|
||||
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();
|
||||
}
|
||||
}
|
16
app/src/main/java/com/idlegandalf/ledd/DrawerFragment.java
Normal file
16
app/src/main/java/com/idlegandalf/ledd/DrawerFragment.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package com.idlegandalf.ledd;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
public class DrawerFragment extends Fragment {
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
// Inflate the layout for this fragment
|
||||
return inflater.inflate(R.layout.drawer_fragment, container, false);
|
||||
}
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
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;
|
||||
}
|
||||
}
|
17
app/src/main/java/com/idlegandalf/ledd/SettingsActivity.java
Normal file
17
app/src/main/java/com/idlegandalf/ledd/SettingsActivity.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package com.idlegandalf.ledd;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
|
||||
public class SettingsActivity extends ActionBarActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
// Display the fragment as the main content.
|
||||
getFragmentManager().beginTransaction()
|
||||
.replace(android.R.id.content, new SettingsFragment())
|
||||
.commit();
|
||||
}
|
||||
}
|
14
app/src/main/java/com/idlegandalf/ledd/SettingsFragment.java
Normal file
14
app/src/main/java/com/idlegandalf/ledd/SettingsFragment.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package com.idlegandalf.ledd;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceFragment;
|
||||
|
||||
public class SettingsFragment extends PreferenceFragment {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Load the preferences from an XML resource
|
||||
addPreferencesFromResource(R.xml.settings);
|
||||
}
|
||||
}
|
@@ -0,0 +1,13 @@
|
||||
package com.idlegandalf.ledd.components;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class Controller {
|
||||
private ArrayList<RGBStripe> stripes;
|
||||
}
|
12
app/src/main/java/com/idlegandalf/ledd/components/HSV.java
Normal file
12
app/src/main/java/com/idlegandalf/ledd/components/HSV.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package com.idlegandalf.ledd.components;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class HSV {
|
||||
private float hue;
|
||||
private float saturation;
|
||||
private float value;
|
||||
}
|
27
app/src/main/java/com/idlegandalf/ledd/components/Host.java
Normal file
27
app/src/main/java/com/idlegandalf/ledd/components/Host.java
Normal file
@@ -0,0 +1,27 @@
|
||||
package com.idlegandalf.ledd.components;
|
||||
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class Host {
|
||||
private String address;
|
||||
private int port;
|
||||
|
||||
public Host(String address, int port) {
|
||||
this.address = address;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public Host() {
|
||||
this.address = null;
|
||||
this.port = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return address + ":" + port;
|
||||
}
|
||||
}
|
@@ -0,0 +1,68 @@
|
||||
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);
|
||||
}
|
||||
}
|
@@ -0,0 +1,17 @@
|
||||
package com.idlegandalf.ledd.components;
|
||||
|
||||
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;
|
||||
|
||||
}
|
@@ -0,0 +1,62 @@
|
||||
package com.idlegandalf.ledd.components;
|
||||
|
||||
|
||||
import org.json.JSONException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class StripeGroup {
|
||||
private String mNiceName;
|
||||
private String mDescription;
|
||||
private ArrayList<RGBStripe> mStripes;
|
||||
|
||||
public String getNiceName() {
|
||||
return mNiceName;
|
||||
}
|
||||
|
||||
public void setNiceName(String mNiceName) {
|
||||
this.mNiceName = mNiceName;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return mDescription;
|
||||
}
|
||||
|
||||
public void setDescription(String mDescription) {
|
||||
this.mDescription = mDescription;
|
||||
}
|
||||
|
||||
public RGBStripe getStripeByPos(int pos) {
|
||||
return mStripes.get(pos);
|
||||
}
|
||||
|
||||
public RGBStripe getStripeById(int sid) {
|
||||
for (int i = 0; i < mStripes.size(); i++) {
|
||||
if (mStripes.get(i).getId() == sid) {
|
||||
return mStripes.get(i);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setRGB(int r, int g, int b, LEDDHelper api) throws JSONException, IOException {
|
||||
for (int i = 0; i < mStripes.size(); i++) {
|
||||
//mStripes.get(i).setRGB(r, g, b, api);
|
||||
}
|
||||
}
|
||||
|
||||
public int addStripe(RGBStripe stripe) {
|
||||
mStripes.add(stripe);
|
||||
return mStripes.size()-1;
|
||||
}
|
||||
|
||||
public void removeStripeByObject(RGBStripe stripe) {
|
||||
for (int i = 0; i < mStripes.size(); i++) {
|
||||
if (mStripes.get(i).getId() == stripe.getId()) {
|
||||
mStripes.remove(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,233 @@
|
||||
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);
|
||||
}
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
package com.idlegandalf.ledd.fragments;
|
||||
|
||||
import android.app.Fragment;
|
||||
|
||||
public class StepStripesFragment extends Fragment {
|
||||
|
||||
}
|
@@ -0,0 +1,218 @@
|
||||
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);
|
||||
}
|
||||
}
|
352
app/src/main/java/com/idlegandalf/ledd/utils/ColorPicker.java
Normal file
352
app/src/main/java/com/idlegandalf/ledd/utils/ColorPicker.java
Normal file
@@ -0,0 +1,352 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,73 @@
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,401 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user