switched to json-rpc (ref LedD d5f403d5573d13e6b8f3113a1c62a096ea721f19)

fixed duplicate connections were made when adding a daemon
This commit is contained in:
Giovanni Harting
2015-10-11 21:52:39 +02:00
parent 6c321aaa90
commit 60f805f15c
26 changed files with 165 additions and 175 deletions

View File

@@ -60,11 +60,12 @@ dependencies {
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.android.support:support-v4:23.0.1'
compile 'com.squareup.okhttp:okhttp:2.5.0'
compile 'com.google.code.gson:gson:2.3.1'
compile 'com.google.code.gson:gson:2.4'
compile 'com.jakewharton:butterknife:7.0.1'
compile 'com.koushikdutta.async:androidasync:2.1.6'
compile 'com.android.support:design:23.0.1'
compile 'com.larswerkman:HoloColorPicker:1.5@aar'
compile 'com.google.guava:guava:19.0-rc1'
compile 'com.google.guava:guava:19.0-rc2'
compile 'com.thetransactioncompany:jsonrpc2-base:1.38'
provided 'org.projectlombok:lombok:1.16.6'
}

Binary file not shown.

View File

@@ -24,6 +24,7 @@
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<application
android:name=".ColorApplication"

View File

@@ -40,6 +40,7 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View;
import android.widget.Button;
import android.widget.Switch;
import com.idlegandalf.ledd.callbacks.RecieveColorCallback;
@@ -75,6 +76,8 @@ public class ColorActivity extends AppCompatActivity implements NavigationView.O
ValueBar valueBar;
@Bind(R.id.switch_onoff)
Switch aSwitch;
@Bind(R.id.music_detection)
Button musicDetection;
private ActionBarDrawerToggle mDrawerToggle;
private refreshDaemonsListener daemonsListener;
private List<LedStripe> ledStripes;
@@ -302,7 +305,7 @@ public class ColorActivity extends AppCompatActivity implements NavigationView.O
}
@Override
public void onGetFailed(String message) {
public void onGetFailed(int code, String message) {
Snackbar.make(findViewById(android.R.id.content), getString(R.string.snackbar_no_connection_stripes) + message, Snackbar
.LENGTH_LONG).show();
@@ -366,7 +369,7 @@ public class ColorActivity extends AppCompatActivity implements NavigationView.O
}
@Override
public void onRecievFailed(String msg) {
public void onRecievFailed(int code, String msg) {
}

View File

@@ -28,6 +28,6 @@ public interface AddControllerCallback extends BaseCallback {
*/
void onControllerAdded(Controller controller);
void onAddFailed(String msg, String detail);
void onAddFailed(int code, String msg);
}

View File

@@ -23,4 +23,6 @@ import com.idlegandalf.ledd.components.LedStripe;
public interface AddStripeCallback extends BaseCallback {
void onAddSuccessfully(LedStripe stripe);
void onAddFailed(int code, String msg);
}

View File

@@ -23,5 +23,5 @@ import com.idlegandalf.ledd.components.LedStripe;
public interface RecieveColorCallback extends BaseCallback {
void onColorRecieved(LedStripe stripe);
void onRecievFailed(String msg);
void onRecievFailed(int code, String msg);
}

View File

@@ -26,5 +26,5 @@ import java.util.List;
public interface StripesCallback extends BaseCallback {
void onSuccess(List<LedStripe> stripes);
void onGetFailed(String message);
void onGetFailed(int code, String message);
}

View File

@@ -19,11 +19,11 @@
package com.idlegandalf.ledd.components;
import org.json.JSONObject;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Response;
public abstract class AnswerTask {
public abstract void onConnectionFailed(String message);
public abstract void onResponse(JSONObject response);
public abstract void onResponse(JSONRPC2Response response);
}

View File

@@ -18,16 +18,16 @@
package com.idlegandalf.ledd.components;
import org.json.JSONObject;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Request;
import lombok.Getter;
@Getter
public class LedDRequest {
JSONObject request;
JSONRPC2Request request;
AnswerTask task;
public LedDRequest(JSONObject request, AnswerTask task) {
public LedDRequest(JSONRPC2Request request, AnswerTask task) {
this.request = request;
this.task = task;
}

View File

@@ -18,33 +18,26 @@
package com.idlegandalf.ledd.components;
import org.json.JSONException;
import org.json.JSONObject;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Request;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Response;
import java.util.UUID;
import org.json.JSONException;
import lombok.Getter;
@Getter
public class Sendable {
LedDDaemon recipient;
JSONObject message;
String ref;
JSONRPC2Request request;
AnswerTask onAnswer;
public Sendable(JSONObject msg, AnswerTask task, LedDDaemon ledDDaemon) throws JSONException {
this(msg, UUID.randomUUID().toString(), task, ledDDaemon);
}
public Sendable(JSONObject msg, String ref, AnswerTask task, LedDDaemon recipient) throws JSONException {
this.message = msg;
this.ref = ref;
this.message.put("ref", ref);
public Sendable(JSONRPC2Request request, AnswerTask task, LedDDaemon recipient) throws JSONException {
this.request = request;
this.onAnswer = task;
this.recipient = recipient;
}
public void onResponse(JSONObject object) {
public void onResponse(JSONRPC2Response object) {
if (onAnswer != null) {
onAnswer.onResponse(object);
}

View File

@@ -190,7 +190,7 @@ public class AddControllerDialog extends DialogFragment implements DialogInterfa
}
@Override
public void onAddFailed(final String msg, String detail) {
public void onAddFailed(final int code, final String msg) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {

View File

@@ -258,7 +258,6 @@ public class AddStripeDialog extends DialogFragment implements DialogInterface.O
LedDHelper helper = ColorApplication.getInstance().getHelperForDaemon((LedDDaemon) daemonSpinner.getSelectedItem());
if (helper != null) {
helper.addStripe(stripe, new AddStripeCallback() {
@Override
@@ -275,6 +274,11 @@ public class AddStripeDialog extends DialogFragment implements DialogInterface.O
dismiss();
}
@Override
public void onAddFailed(int code, String msg) {
}
@Override
public void onConnectionFailed(final String message) {
getActivity().runOnUiThread(new Runnable() {
@@ -415,7 +419,7 @@ public class AddStripeDialog extends DialogFragment implements DialogInterface.O
}
@Override
public void onGetFailed(String message) {
public void onGetFailed(int code, String message) {
}

View File

@@ -38,13 +38,19 @@ import com.idlegandalf.ledd.components.LedDDaemon;
import com.idlegandalf.ledd.components.LedDRequest;
import com.idlegandalf.ledd.components.LedStripe;
import com.idlegandalf.ledd.services.ColorService;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Error;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Request;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Response;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.LinkedBlockingQueue;
public class LedDHelper {
@@ -52,7 +58,7 @@ public class LedDHelper {
final String ACTION_GETCOLOR = "get_color";
final String ACTION_ADDCONTROLLER = "add_controller";
final String ACTION_GETALLSTRIPES = "get_stripes";
final String ACTION_ADDSTRIPES = "add_stripe";
final String ACTION_ADDSTRIPE = "add_stripe";
final String ACTION_TESTCHANNEL = "test_channel";
final String ACTION_DISCOVER = "discover";
private Context context;
@@ -92,34 +98,33 @@ public class LedDHelper {
* @param c controller object
*/
public void addController(final Controller c, final AddControllerCallback callback) {
JSONObject jnson = new JSONObject();
Map<String, Object> params = new HashMap<>();
try {
jnson.put("action", ACTION_ADDCONTROLLER);
jnson.put("channels", c.getChannels());
jnson.put("i2c_dev", c.getI2c_device());
jnson.put("address", c.getAddress());
} catch (JSONException e) {
e.printStackTrace();
}
params.put("channels", c.getChannels());
params.put("i2c_dev", c.getI2c_device());
params.put("address", c.getAddress());
addRequestToQueue(jnson, new AnswerTask() {
JSONRPC2Request request = new JSONRPC2Request(ACTION_ADDCONTROLLER, params, UUID.randomUUID().toString());
addRequestToQueue(request, new AnswerTask() {
@Override
public void onConnectionFailed(String message) {
callback.onAddFailed(message, "");
callback.onConnectionFailed(message);
}
@Override
public void onResponse(JSONObject response) {
try {
if (response.getBoolean("success")) {
c.setId(response.getInt("cid"));
public void onResponse(JSONRPC2Response response) {
if (response.indicatesSuccess()) {
try {
JSONObject json = new JSONObject(response.getResult().toString());
c.setId(json.getInt("cid"));
callback.onControllerAdded(c);
} else {
callback.onAddFailed(response.getString("message"), response.getString("message_detail"));
} catch (JSONException e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
} else {
@SuppressWarnings("ThrowableResultOfMethodCallIgnored") JSONRPC2Error error = response.getError();
callback.onAddFailed(error.getCode(), error.getMessage());
}
}
});
@@ -129,27 +134,20 @@ public class LedDHelper {
* Get stripes known to daemon
*/
public void getStripes(final StripesCallback callback) {
JSONObject jnson = new JSONObject();
try {
jnson.put("action", ACTION_GETALLSTRIPES);
} catch (JSONException e) {
e.printStackTrace();
}
addRequestToQueue(jnson, new AnswerTask() {
addRequestToQueue(new JSONRPC2Request(ACTION_GETALLSTRIPES, UUID.randomUUID().toString()), new AnswerTask() {
@Override
public void onConnectionFailed(String message) {
callback.onGetFailed(message);
callback.onConnectionFailed(message);
}
@Override
public void onResponse(JSONObject response) {
public void onResponse(JSONRPC2Response response) {
try {
if (response.getBoolean("success")) {
if (response.indicatesSuccess()) {
ledDDaemon.getControllers().clear();
List<LedStripe> list = new ArrayList<>();
JSONArray jcontrollers = response.getJSONArray("controller");
JSONObject json = new JSONObject(response.getResult().toString());
JSONArray jcontrollers = json.getJSONArray("controller");
for (int i = 0; i < jcontrollers.length(); i++) {
JSONObject row = jcontrollers.getJSONObject(i);
@@ -180,8 +178,8 @@ public class LedDHelper {
callback.onSuccess(list);
} else {
if (response.has("message")) callback.onGetFailed(response.getString("message"));
else callback.onGetFailed("unknown error");
@SuppressWarnings("ThrowableResultOfMethodCallIgnored") JSONRPC2Error error = response.getError();
callback.onGetFailed(error.getCode(), error.getMessage());
}
} catch (Exception e) {
e.printStackTrace();
@@ -196,26 +194,20 @@ public class LedDHelper {
* @param ledStripe Stripe
*/
public void setColor(LedStripe ledStripe) {
Map<String, Object> hsv = new HashMap<>();
JSONObject jnson = new JSONObject();
JSONObject hsv = new JSONObject();
hsv.put("h", ledStripe.getColor().getHue());
hsv.put("s", ledStripe.getColor().getSaturation());
hsv.put("v", ledStripe.getColor().getValue());
try {
hsv.put("h", ledStripe.getColor().getHue());
hsv.put("s", ledStripe.getColor().getSaturation());
hsv.put("v", ledStripe.getColor().getValue());
Map<String, Object> params = new HashMap<>();
params.put("sid", ledStripe.getId());
params.put("hsv", hsv);
jnson.put("action", ACTION_SETCOLOR);
jnson.put("sid", ledStripe.getId());
jnson.put("hsv", hsv);
JSONRPC2Request request = new JSONRPC2Request(ACTION_SETCOLOR, params, UUID.randomUUID().toString());
} catch (JSONException e) {
e.printStackTrace();
}
addRequestToQueue(jnson, null);
addRequestToQueue(request, null);
}
/**
@@ -224,33 +216,29 @@ public class LedDHelper {
* @param ledStripe Stripe
*/
public void getColor(final LedStripe ledStripe, final RecieveColorCallback callback) {
JSONObject jnson = new JSONObject();
HashMap<String, Object> params = new HashMap<>();
params.put("sid", ledStripe.getId());
try {
jnson.put("action", ACTION_GETCOLOR);
jnson.put("sid", ledStripe.getId());
} catch (JSONException e) {
e.printStackTrace();
}
addRequestToQueue(jnson, new AnswerTask() {
addRequestToQueue(new JSONRPC2Request(ACTION_GETCOLOR, params, UUID.randomUUID().toString()), new AnswerTask() {
@Override
public void onConnectionFailed(String message) {
callback.onRecievFailed(message);
callback.onConnectionFailed(message);
}
@Override
public void onResponse(JSONObject response) {
try {
if (response.getBoolean("success")) {
JSONArray hsv = response.getJSONArray("color");
public void onResponse(JSONRPC2Response response) {
if (response.indicatesSuccess()) {
try {
JSONObject json = new JSONObject(response.getResult().toString());
JSONArray hsv = json.getJSONArray("color");
ledStripe.setColor(new HSV(hsv.getDouble(0), hsv.getDouble(1), hsv.getDouble(2)));
callback.onColorRecieved(ledStripe);
} else {
callback.onRecievFailed(response.getString("message"));
} catch (JSONException e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
} else {
@SuppressWarnings("ThrowableResultOfMethodCallIgnored") JSONRPC2Error error = response.getError();
callback.onRecievFailed(error.getCode(), error.getMessage());
}
}
});
@@ -264,26 +252,20 @@ public class LedDHelper {
* @param value value (1= on, 0 = off)
*/
public void testChannel(Controller c, int channel, int value) {
JSONObject jnson = new JSONObject();
HashMap<String, Object> params = new HashMap<>();
try {
jnson.put("action", ACTION_TESTCHANNEL);
params.put("cid", c.getId());
params.put("channel", channel);
params.put("value", value);
jnson.put("cid", c.getId());
jnson.put("channel", channel);
jnson.put("value", value);
} catch (JSONException e) {
e.printStackTrace();
}
addRequestToQueue(jnson, new AnswerTask() {
addRequestToQueue(new JSONRPC2Request(ACTION_TESTCHANNEL, params, UUID.randomUUID().toString()), new AnswerTask() {
@Override
public void onConnectionFailed(String message) {
}
@Override
public void onResponse(JSONObject response) {
public void onResponse(JSONRPC2Response response) {
}
});
@@ -293,25 +275,18 @@ public class LedDHelper {
* Get information about an ledd daemon
*/
public void discover(final DiscoverCallback callback) {
JSONObject jnson = new JSONObject();
try {
jnson.put("action", ACTION_DISCOVER);
} catch (JSONException e) {
e.printStackTrace();
}
addRequestToQueue(jnson, new AnswerTask() {
addRequestToQueue(new JSONRPC2Request(ACTION_DISCOVER, UUID.randomUUID().toString()), new AnswerTask() {
@Override
public void onConnectionFailed(String message) {
callback.onConnectionFailed(message);
}
@Override
public void onResponse(JSONObject response) {
public void onResponse(JSONRPC2Response response) {
try {
if (response.getBoolean("success")) {
callback.onDiscoverSuccessfully(response.getString("version"));
if (response.indicatesSuccess()) {
JSONObject json = new JSONObject(response.getResult().toString());
callback.onDiscoverSuccessfully(json.getString("version"));
}
} catch (Exception e) {
e.printStackTrace();
@@ -324,40 +299,34 @@ public class LedDHelper {
* Get information about an ledd daemon
*/
public void addStripe(final LedStripe ledStripe, final AddStripeCallback callback) {
JSONObject jnson = new JSONObject();
HashMap<String, Object> params = new HashMap<>();
HashMap<String, Object> mapping = new HashMap<>();
try {
jnson.put("action", ACTION_ADDSTRIPES);
params.put("name", ledStripe.getName());
params.put("rgb", ledStripe.isRGB());
JSONObject stripe = new JSONObject();
mapping.put("r", ledStripe.getChannelRed());
mapping.put("g", ledStripe.getChannelGreen());
mapping.put("b", ledStripe.getChannelBlue());
params.put("map", mapping);
params.put("cid", ledStripe.getController().getId());
stripe.put("name", ledStripe.getName());
stripe.put("rgb", ledStripe.isRGB());
JSONObject mapping = new JSONObject();
mapping.put("r", ledStripe.getChannelRed());
mapping.put("g", ledStripe.getChannelGreen());
mapping.put("b", ledStripe.getChannelBlue());
stripe.put("map", mapping);
stripe.put("cid", ledStripe.getController().getId());
jnson.put("stripe", stripe);
} catch (JSONException e) {
e.printStackTrace();
}
addRequestToQueue(jnson, new AnswerTask() {
addRequestToQueue(new JSONRPC2Request(ACTION_ADDSTRIPE, params, UUID.randomUUID().toString()), new AnswerTask() {
@Override
public void onConnectionFailed(String message) {
callback.onConnectionFailed(message);
}
@Override
public void onResponse(JSONObject response) {
public void onResponse(JSONRPC2Response response) {
try {
if (response.getBoolean("success")) {
ledStripe.setId(response.getInt("sid"));
if (response.indicatesSuccess()) {
JSONObject json = new JSONObject(response.getResult().toString());
ledStripe.setId(json.getInt("sid"));
callback.onAddSuccessfully(ledStripe);
} else {
@SuppressWarnings("ThrowableResultOfMethodCallIgnored") JSONRPC2Error error = response.getError();
callback.onAddFailed(error.getCode(), error.getMessage());
}
} catch (Exception e) {
e.printStackTrace();
@@ -366,8 +335,8 @@ public class LedDHelper {
});
}
private void addRequestToQueue(JSONObject json, AnswerTask task) {
if (json != null && json.length() > 0) dRequests.add(new LedDRequest(json, task));
private void addRequestToQueue(JSONRPC2Request request, AnswerTask task) {
if (request != null) dRequests.add(new LedDRequest(request, task));
}
public void teardown() {

View File

@@ -33,9 +33,11 @@ import com.koushikdutta.async.DataEmitter;
import com.koushikdutta.async.Util;
import com.koushikdutta.async.callback.ConnectCallback;
import com.koushikdutta.async.callback.DataCallback;
import com.thetransactioncompany.jsonrpc2.JSONRPC2ParseException;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Request;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Response;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
@@ -80,19 +82,24 @@ public class ColorService extends Service {
DataCallback dataCallback = new DataCallback() {
@Override
public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
try {
JSONObject resp = new JSONObject(new String(bb.getAllByteArray()));
JSONRPC2Response reqIn = null;
if (sendableHashMap.containsKey(resp.getString("ref"))) {
sendableHashMap.get(resp.getString("ref")).onResponse(resp);
sendableHashMap.remove(resp.getString("ref"));
if (timeoutHashMap.containsKey(resp.getString("ref")) && timeoutHashMap.get(resp.getString("ref")) != null)
timeoutHashMap.get(resp.getString("ref")).cancel(false);
timeoutHashMap.remove(resp.getString("ref"));
}
} catch (JSONException e) {
try {
reqIn = JSONRPC2Response.parse(new String(bb.getAllByteArray()));
} catch (JSONRPC2ParseException e) {
e.printStackTrace();
}
if (reqIn != null) {
if (sendableHashMap.containsKey(reqIn.getID().toString())) {
sendableHashMap.get(reqIn.getID().toString()).onResponse(reqIn);
sendableHashMap.remove(reqIn.getID().toString());
if (timeoutHashMap.containsKey(reqIn.getID().toString()) && timeoutHashMap.get(reqIn.getID().toString()) != null)
timeoutHashMap.get(reqIn.getID().toString()).cancel(false);
timeoutHashMap.remove(reqIn.getID().toString());
}
}
}
};
@@ -111,22 +118,32 @@ public class ColorService extends Service {
if (item instanceof Sendable) {
final Sendable sendable = (Sendable) item;
if (socketHashMap.containsKey(sendable.getRecipient()) && socketHashMap.get(sendable.getRecipient()).getServer().isRunning
()) {
if (socketHashMap.containsKey(sendable.getRecipient())) {
if (socketHashMap.get(sendable.getRecipient()) == null) {
// if server is not running yet, readd item to queue
workQueue.add(item);
continue;
} else if (!socketHashMap.get(sendable.getRecipient()).getServer().isRunning()) {
// connection probably closed or was interrupted -> reconnect
socketHashMap.remove(sendable.getRecipient());
workQueue.add(item);
continue;
}
Util.writeAll(socketHashMap.get(sendable.getRecipient()), (sendable.getMessage().toString() + "\n").getBytes("UTF-8"),
Util.writeAll(socketHashMap.get(sendable.getRecipient()), (sendable.getRequest().toString() + "\n").getBytes("UTF-8"),
null);
sendableHashMap.put(sendable.getRef(), sendable);
sendableHashMap.put((String) sendable.getRequest().getID(), sendable);
if (!poolExecutor.isTerminating() && !poolExecutor.isTerminated())
timeoutHashMap.put(sendable.getRef(), poolExecutor.schedule(new Runnable() {
timeoutHashMap.put((String) sendable.getRequest().getID(), poolExecutor.schedule(new Runnable() {
@Override
public void run() {
sendable.onNoResponse();
timeoutHashMap.remove(sendable.getRef());
sendableHashMap.remove(sendable.getRef());
timeoutHashMap.remove(sendable.getRequest().getID());
sendableHashMap.remove(sendable.getRequest().getID());
}
}, 1000, TimeUnit.MILLISECONDS));
} else {
socketHashMap.put(sendable.getRecipient(), null);
AsyncServer.getDefault().connectSocket(new InetSocketAddress(sendable.getRecipient().getAddress(), sendable
.getRecipient().getPort()), new ConnectCallback() {
@Override
@@ -160,10 +177,10 @@ public class ColorService extends Service {
}
public class ColorBinder extends Binder {
public void queueSend(LedDDaemon rec, JSONObject msg, AnswerTask answerTask) {
public void queueSend(LedDDaemon rec, JSONRPC2Request request, AnswerTask answerTask) {
Sendable sendable = null;
try {
sendable = new Sendable(msg, answerTask, rec);
sendable = new Sendable(request, answerTask, rec);
} catch (JSONException e) {
e.printStackTrace();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 347 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 436 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 511 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 524 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 665 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 702 B

View File

@@ -18,26 +18,26 @@
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="192dp"
android:background="?attr/colorPrimaryDark"
android:gravity="bottom"
android:padding="16dp"
android:theme="@style/ThemeOverlay.AppCompat.Dark">
android:layout_width="match_parent"
android:layout_height="192dp"
android:background="?attr/colorPrimaryDark"
android:gravity="bottom"
android:padding="16dp"
android:theme="@style/ThemeOverlay.AppCompat.Dark">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:text="-- stripes infos go here --"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"/>
<ImageButton
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:background="?android:attr/selectableItemBackground"
android:scaleType="fitCenter"
android:src="@drawable/ic_clear_white_48dp"/>
</RelativeLayout>