Initial commit from non tracked working directory

This commit is contained in:
Giovanni Harting
2015-08-13 03:27:24 +02:00
parent 7fbc976571
commit 792cc20cd1
74 changed files with 2990 additions and 0 deletions

View File

@@ -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();
}
}
}

View 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();
}
}

View 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;
}
}

View 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();
}
}

View 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);
}
}

View File

@@ -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;
}
}

View 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();
}
}

View 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);
}
}

View File

@@ -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;
}

View 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;
}

View 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;
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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;
}
}
}
}

View File

@@ -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);
}
}

View File

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

View File

@@ -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);
}
}

View 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);
}
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}
}