mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2025-02-03 21:47:32 +01:00
Fossil Hybrid HR: Use embedded preview image from .wapp file during import
This commit is contained in:
parent
c490b4050d
commit
75dd5f1863
@ -18,6 +18,7 @@
|
|||||||
package nodomain.freeyourgadget.gadgetbridge.adapter;
|
package nodomain.freeyourgadget.gadgetbridge.adapter;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@ -87,11 +88,13 @@ public abstract class AbstractItemAdapter<T> extends ArrayAdapter<T> {
|
|||||||
ImageView iconView = (ImageView) view.findViewById(R.id.item_image);
|
ImageView iconView = (ImageView) view.findViewById(R.id.item_image);
|
||||||
TextView nameView = (TextView) view.findViewById(R.id.item_name);
|
TextView nameView = (TextView) view.findViewById(R.id.item_name);
|
||||||
TextView detailsView = (TextView) view.findViewById(R.id.item_details);
|
TextView detailsView = (TextView) view.findViewById(R.id.item_details);
|
||||||
|
ImageView previewView = (ImageView) view.findViewById(R.id.item_preview);
|
||||||
|
|
||||||
nameView.setText(getName(item));
|
nameView.setText(getName(item));
|
||||||
detailsView.setText(getDetails(item));
|
detailsView.setText(getDetails(item));
|
||||||
iconView.setImageResource(getIcon(item));
|
iconView.setImageResource(getIcon(item));
|
||||||
iconView.setBackgroundColor(backgroundColor);
|
iconView.setBackgroundColor(backgroundColor);
|
||||||
|
previewView.setImageBitmap(getPreview(item));
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
@ -103,6 +106,8 @@ public abstract class AbstractItemAdapter<T> extends ArrayAdapter<T> {
|
|||||||
@DrawableRes
|
@DrawableRes
|
||||||
protected abstract int getIcon(T item);
|
protected abstract int getIcon(T item);
|
||||||
|
|
||||||
|
protected abstract Bitmap getPreview(T item);
|
||||||
|
|
||||||
public void setSize(int size) {
|
public void setSize(int size) {
|
||||||
this.size = size;
|
this.size = size;
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package nodomain.freeyourgadget.gadgetbridge.adapter;
|
package nodomain.freeyourgadget.gadgetbridge.adapter;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -46,4 +47,8 @@ public class ItemWithDetailsAdapter extends AbstractItemAdapter<ItemWithDetails>
|
|||||||
return item.getIcon();
|
return item.getIcon();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Bitmap getPreview(ItemWithDetails item) {
|
||||||
|
return item.getPreview();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package nodomain.freeyourgadget.gadgetbridge.devices.qhybrid;
|
package nodomain.freeyourgadget.gadgetbridge.devices.qhybrid;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
@ -37,6 +38,8 @@ import java.util.ArrayList;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp;
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.image.ImageConverter;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.BitmapUtil;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.UriHelper;
|
import nodomain.freeyourgadget.gadgetbridge.util.UriHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -64,6 +67,11 @@ public class FossilFileReader {
|
|||||||
private int config_start;
|
private int config_start;
|
||||||
private int file_end;
|
private int file_end;
|
||||||
|
|
||||||
|
ArrayList<String> filenamesIcons;
|
||||||
|
ArrayList<String> filenamesLayout;
|
||||||
|
ArrayList<String> filenamesDisplayName;
|
||||||
|
ArrayList<String> filenamesConfig;
|
||||||
|
|
||||||
|
|
||||||
public FossilFileReader(Uri uri, Context context) throws IOException {
|
public FossilFileReader(Uri uri, Context context) throws IOException {
|
||||||
this.uri = uri;
|
this.uri = uri;
|
||||||
@ -155,10 +163,10 @@ public class FossilFileReader {
|
|||||||
mAppKeys.put("name", foundName);
|
mAppKeys.put("name", foundName);
|
||||||
mAppKeys.put("uuid", UUID.nameUUIDFromBytes(foundName.getBytes(StandardCharsets.UTF_8)));
|
mAppKeys.put("uuid", UUID.nameUUIDFromBytes(foundName.getBytes(StandardCharsets.UTF_8)));
|
||||||
}
|
}
|
||||||
ArrayList<String> filenamesIcons = parseAppFilenames(buf, layout_start,false);
|
filenamesIcons = parseAppFilenames(buf, layout_start,false);
|
||||||
ArrayList<String> filenamesLayout = parseAppFilenames(buf, display_name_start,true);
|
filenamesLayout = parseAppFilenames(buf, display_name_start,true);
|
||||||
ArrayList<String> filenamesDisplayName = parseAppFilenames(buf, config_start,true);
|
filenamesDisplayName = parseAppFilenames(buf, config_start,true);
|
||||||
ArrayList<String> filenamesConfig = parseAppFilenames(buf, file_end,true);
|
filenamesConfig = parseAppFilenames(buf, file_end,true);
|
||||||
|
|
||||||
if (filenamesDisplayName.contains("theme_class")) {
|
if (filenamesDisplayName.contains("theme_class")) {
|
||||||
isApp = false;
|
isApp = false;
|
||||||
@ -197,6 +205,22 @@ public class FossilFileReader {
|
|||||||
return new JSONObject(jsonTokener);
|
return new JSONObject(jsonTokener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Bitmap getPreview() {
|
||||||
|
try {
|
||||||
|
if ((filenamesIcons != null) && (filenamesIcons.contains("!preview.rle"))) {
|
||||||
|
return BitmapUtil.getCircularBitmap(ImageConverter.decodeFromRLEImage(getImageFileContents("!preview.rle")));
|
||||||
|
}
|
||||||
|
if ((filenamesIcons != null) && (filenamesIcons.contains("!preview"))) {
|
||||||
|
return BitmapUtil.getCircularBitmap(ImageConverter.decodeFromRLEImage(getImageFileContents("!preview")));
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.warn("Couldn't read preview image from wapp file: ", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
LOG.warn("No preview image found in wapp file");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private byte[] getImageFileContents(String filename) throws IOException {
|
private byte[] getImageFileContents(String filename) throws IOException {
|
||||||
return getFileContentsByName(filename, appIconStart, layout_start, false);
|
return getFileContentsByName(filename, appIconStart, layout_start, false);
|
||||||
}
|
}
|
||||||
|
@ -79,6 +79,11 @@ public class FossilHRInstallHandler implements InstallHandler {
|
|||||||
GenericItem installItem = new GenericItem();
|
GenericItem installItem = new GenericItem();
|
||||||
installItem.setName(fossilFile.getName());
|
installItem.setName(fossilFile.getName());
|
||||||
installItem.setDetails(fossilFile.getVersion());
|
installItem.setDetails(fossilFile.getVersion());
|
||||||
|
Bitmap preview = fossilFile.getPreview();
|
||||||
|
if (preview != null) {
|
||||||
|
preview = Bitmap.createScaledBitmap(preview, preview.getWidth() * 3, preview.getHeight() * 3, false);
|
||||||
|
}
|
||||||
|
installItem.setPreview(preview);
|
||||||
if (fossilFile.isFirmware()) {
|
if (fossilFile.isFirmware()) {
|
||||||
installItem.setIcon(R.drawable.ic_firmware);
|
installItem.setIcon(R.drawable.ic_firmware);
|
||||||
installActivity.setInfoText(mContext.getString(R.string.firmware_install_warning, "(unknown)"));
|
installActivity.setInfoText(mContext.getString(R.string.firmware_install_warning, "(unknown)"));
|
||||||
@ -106,12 +111,12 @@ public class FossilHRInstallHandler implements InstallHandler {
|
|||||||
if (fossilFile.isFirmware()) {
|
if (fossilFile.isFirmware()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
saveAppInCache(fossilFile, null, mCoordinator, mContext);
|
saveAppInCache(fossilFile, null, fossilFile.getPreview(), mCoordinator, mContext);
|
||||||
// refresh list
|
// refresh list
|
||||||
manager.sendBroadcast(new Intent(AbstractAppManagerFragment.ACTION_REFRESH_APPLIST));
|
manager.sendBroadcast(new Intent(AbstractAppManagerFragment.ACTION_REFRESH_APPLIST));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void saveAppInCache(FossilFileReader fossilFile, Bitmap backgroundImg, DeviceCoordinator mCoordinator, Context mContext) {
|
public static void saveAppInCache(FossilFileReader fossilFile, Bitmap backgroundImg, Bitmap previewImg, DeviceCoordinator mCoordinator, Context mContext) {
|
||||||
GBDeviceApp app;
|
GBDeviceApp app;
|
||||||
File destDir;
|
File destDir;
|
||||||
// write app file
|
// write app file
|
||||||
@ -150,7 +155,7 @@ public class FossilHRInstallHandler implements InstallHandler {
|
|||||||
}
|
}
|
||||||
// write watchface background image
|
// write watchface background image
|
||||||
if (backgroundImg != null) {
|
if (backgroundImg != null) {
|
||||||
outputFile = new File(destDir, app.getUUID().toString() + ".png");
|
outputFile = new File(destDir, app.getUUID().toString() + "_bg.png");
|
||||||
try {
|
try {
|
||||||
FileOutputStream fos = new FileOutputStream(outputFile);
|
FileOutputStream fos = new FileOutputStream(outputFile);
|
||||||
backgroundImg.compress(Bitmap.CompressFormat.PNG, 9, fos);
|
backgroundImg.compress(Bitmap.CompressFormat.PNG, 9, fos);
|
||||||
@ -159,6 +164,17 @@ public class FossilHRInstallHandler implements InstallHandler {
|
|||||||
LOG.error("Failed to write to output file: " + e.getMessage(), e);
|
LOG.error("Failed to write to output file: " + e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// write watchface preview image
|
||||||
|
if (previewImg != null) {
|
||||||
|
outputFile = new File(destDir, app.getUUID().toString() + "_preview.png");
|
||||||
|
try {
|
||||||
|
FileOutputStream fos = new FileOutputStream(outputFile);
|
||||||
|
previewImg.compress(Bitmap.CompressFormat.PNG, 9, fos);
|
||||||
|
fos.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.error("Failed to write to output file: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -329,7 +329,10 @@ public class HybridHRWatchfaceDesignerActivity extends AbstractGBActivity implem
|
|||||||
LOG.warn("Could not get external dir while trying to access app cache.", e);
|
LOG.warn("Could not get external dir while trying to access app cache.", e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
File backgroundFile = new File(appCacheDir, appUUID + ".png");
|
File backgroundFile = new File(appCacheDir, appUUID + "_bg.png");
|
||||||
|
if (!backgroundFile.exists()) {
|
||||||
|
backgroundFile = new File(appCacheDir, appUUID + ".png");
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
Bitmap cachedBackground = BitmapFactory.decodeStream(new FileInputStream(backgroundFile));
|
Bitmap cachedBackground = BitmapFactory.decodeStream(new FileInputStream(backgroundFile));
|
||||||
selectedBackgroundImage = BitmapUtil.convertToGrayscale(BitmapUtil.getCircularBitmap(cachedBackground));
|
selectedBackgroundImage = BitmapUtil.convertToGrayscale(BitmapUtil.getCircularBitmap(cachedBackground));
|
||||||
@ -561,7 +564,8 @@ public class HybridHRWatchfaceDesignerActivity extends AbstractGBActivity implem
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void sendToWatch(boolean preview) {
|
private void sendToWatch(boolean preview) {
|
||||||
HybridHRWatchfaceFactory wfFactory;
|
final Context mContext = this;
|
||||||
|
final HybridHRWatchfaceFactory wfFactory;
|
||||||
if (preview) {
|
if (preview) {
|
||||||
wfFactory = new HybridHRWatchfaceFactory("previewWatchface");
|
wfFactory = new HybridHRWatchfaceFactory("previewWatchface");
|
||||||
} else {
|
} else {
|
||||||
@ -603,20 +607,15 @@ public class HybridHRWatchfaceDesignerActivity extends AbstractGBActivity implem
|
|||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
findViewById(R.id.watchface_upload_progress_bar).setVisibility(View.VISIBLE);
|
findViewById(R.id.watchface_upload_progress_bar).setVisibility(View.VISIBLE);
|
||||||
GBApplication.deviceService().onInstallApp(tempAppFileUri);
|
GBApplication.deviceService().onInstallApp(tempAppFileUri);
|
||||||
FossilHRInstallHandler.saveAppInCache(fossilFile, processedBackgroundImage, mCoordinator, HybridHRWatchfaceDesignerActivity.this);
|
FossilHRInstallHandler.saveAppInCache(fossilFile, processedBackgroundImage, wfFactory.getPreviewImage(mContext), mCoordinator, HybridHRWatchfaceDesignerActivity.this);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.show();
|
.show();
|
||||||
} else {
|
} else {
|
||||||
findViewById(R.id.watchface_upload_progress_bar).setVisibility(View.VISIBLE);
|
findViewById(R.id.watchface_upload_progress_bar).setVisibility(View.VISIBLE);
|
||||||
GBApplication.deviceService().onInstallApp(tempAppFileUri);
|
GBApplication.deviceService().onInstallApp(tempAppFileUri);
|
||||||
FossilHRInstallHandler.saveAppInCache(fossilFile, processedBackgroundImage, mCoordinator, HybridHRWatchfaceDesignerActivity.this);
|
FossilHRInstallHandler.saveAppInCache(fossilFile, processedBackgroundImage, wfFactory.getPreviewImage(mContext), mCoordinator, HybridHRWatchfaceDesignerActivity.this);
|
||||||
}
|
}
|
||||||
Bitmap previewImage = wfFactory.getPreviewImage(this);
|
|
||||||
File previewFile = new File(cacheDir, app.getUUID().toString() + "_preview.png");
|
|
||||||
FileOutputStream previewFOS = new FileOutputStream(previewFile);
|
|
||||||
previewImage.compress(Bitmap.CompressFormat.PNG, 9, previewFOS);
|
|
||||||
previewFOS.close();
|
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LOG.warn("Error while creating and uploading watchface", e);
|
LOG.warn("Error while creating and uploading watchface", e);
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
package nodomain.freeyourgadget.gadgetbridge.model;
|
package nodomain.freeyourgadget.gadgetbridge.model;
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
|
||||||
@ -27,6 +28,7 @@ public class GenericItem implements ItemWithDetails {
|
|||||||
private String details;
|
private String details;
|
||||||
private int icon;
|
private int icon;
|
||||||
private boolean warning = false;
|
private boolean warning = false;
|
||||||
|
private Bitmap preview;
|
||||||
|
|
||||||
public static final Parcelable.Creator CREATOR = new Parcelable.Creator<GenericItem>() {
|
public static final Parcelable.Creator CREATOR = new Parcelable.Creator<GenericItem>() {
|
||||||
@Override
|
@Override
|
||||||
@ -106,6 +108,14 @@ public class GenericItem implements ItemWithDetails {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setPreview(Bitmap preview) {
|
||||||
|
this.preview = preview;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bitmap getPreview() {
|
||||||
|
return preview;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (o == null || getClass() != o.getClass()) {
|
if (o == null || getClass() != o.getClass()) {
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
package nodomain.freeyourgadget.gadgetbridge.model;
|
package nodomain.freeyourgadget.gadgetbridge.model;
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
|
||||||
public interface ItemWithDetails extends Parcelable, Comparable<ItemWithDetails> {
|
public interface ItemWithDetails extends Parcelable, Comparable<ItemWithDetails> {
|
||||||
@ -25,6 +26,8 @@ public interface ItemWithDetails extends Parcelable, Comparable<ItemWithDetails>
|
|||||||
|
|
||||||
int getIcon();
|
int getIcon();
|
||||||
|
|
||||||
|
Bitmap getPreview();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Equality is based on #getName() only.
|
* Equality is based on #getName() only.
|
||||||
*
|
*
|
||||||
|
@ -21,12 +21,20 @@ import android.graphics.Color;
|
|||||||
|
|
||||||
import androidx.annotation.ColorInt;
|
import androidx.annotation.ColorInt;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.FossilFileReader;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.encoder.RLEEncoder;
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.encoder.RLEEncoder;
|
||||||
|
|
||||||
public class ImageConverter {
|
public class ImageConverter {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(ImageConverter.class);
|
||||||
|
|
||||||
public static byte[] get2BitsRLEImageBytes(Bitmap bitmap) {
|
public static byte[] get2BitsRLEImageBytes(Bitmap bitmap) {
|
||||||
int[] pixels = new int[bitmap.getWidth() * bitmap.getHeight()];
|
int[] pixels = new int[bitmap.getWidth() * bitmap.getHeight()];
|
||||||
bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
|
bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
|
||||||
@ -93,4 +101,58 @@ public class ImageConverter {
|
|||||||
sum /= 3;
|
sum /= 3;
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Bitmap decodeFromRLEImage(byte[] rleImage) {
|
||||||
|
ByteBuffer buf = ByteBuffer.wrap(rleImage);
|
||||||
|
buf.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
int width = Byte.toUnsignedInt(buf.get());
|
||||||
|
int height = Byte.toUnsignedInt(buf.get());
|
||||||
|
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||||
|
int posX = 0;
|
||||||
|
int posY = 0;
|
||||||
|
while (buf.remaining() > 2) {
|
||||||
|
int repetitions = Byte.toUnsignedInt(buf.get());
|
||||||
|
int pixel = Byte.toUnsignedInt(buf.get());
|
||||||
|
int color = pixel << 6;
|
||||||
|
int combinedColor = Color.rgb(color, color, color);
|
||||||
|
for (int i=0; i<repetitions; i++) {
|
||||||
|
bitmap.setPixel(posX, posY, combinedColor);
|
||||||
|
posX++;
|
||||||
|
if (posX >= width) {
|
||||||
|
posX = 0;
|
||||||
|
posY++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Bitmap decodeFromRAWImage(byte[] rawImage, int width, int height) {
|
||||||
|
int imageSize = rawImage.length;
|
||||||
|
if (imageSize * 4 != width * height) {
|
||||||
|
// imageSize is multiplied by 4 because there are 2-bit pixels stored in every byte
|
||||||
|
LOG.warn("decodeFromRAWImage: provided pixels (" + imageSize * 4 + ") not equal to resolution " + width + "*" + height);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ByteBuffer buf = ByteBuffer.wrap(rawImage);
|
||||||
|
buf.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||||
|
int posX = 0;
|
||||||
|
int posY = 0;
|
||||||
|
while (buf.remaining() > 0) {
|
||||||
|
int currentPixels = Byte.toUnsignedInt(buf.get());
|
||||||
|
for (int shift=0; shift<=6; shift+=2) {
|
||||||
|
//for (int shift=6; shift>=0; shift-=2) {
|
||||||
|
int color = ((currentPixels >> shift) & 0b00000011) << 6;
|
||||||
|
int combinedColor = Color.rgb(color, color, color);
|
||||||
|
bitmap.setPixel(posX, posY, combinedColor);
|
||||||
|
posX++;
|
||||||
|
if (posX >= width) {
|
||||||
|
posX = 0;
|
||||||
|
posY++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,20 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?android:attr/activatedBackgroundIndicator">
|
android:background="?android:attr/activatedBackgroundIndicator">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/item_preview"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentStart="false"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:contentDescription="Item preview" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/item_image"
|
android:id="@+id/item_image"
|
||||||
android:layout_width="56dp"
|
android:layout_width="56dp"
|
||||||
android:layout_height="56dp"
|
android:layout_height="56dp"
|
||||||
android:layout_alignParentStart="true"
|
android:layout_below="@+id/item_preview"
|
||||||
android:contentDescription="@string/candidate_item_device_image"
|
android:contentDescription="@string/candidate_item_device_image"
|
||||||
android:padding="8dp" />
|
android:padding="8dp" />
|
||||||
|
|
||||||
@ -17,6 +26,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_centerVertical="true"
|
android:layout_centerVertical="true"
|
||||||
android:layout_toEndOf="@+id/item_image"
|
android:layout_toEndOf="@+id/item_image"
|
||||||
|
android:layout_below="@+id/item_preview"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:paddingStart="8dp"
|
android:paddingStart="8dp"
|
||||||
android:paddingEnd="8dp">
|
android:paddingEnd="8dp">
|
||||||
|
@ -5,11 +5,19 @@
|
|||||||
android:background="?android:attr/activatedBackgroundIndicator"
|
android:background="?android:attr/activatedBackgroundIndicator"
|
||||||
android:paddingStart="1dp">
|
android:paddingStart="1dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/item_preview"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:contentDescription="Item preview" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/item_image"
|
android:id="@+id/item_image"
|
||||||
android:layout_width="8dp"
|
android:layout_width="8dp"
|
||||||
android:layout_height="8dp"
|
android:layout_height="8dp"
|
||||||
android:layout_alignParentStart="true"
|
android:layout_toEndOf="@+id/item_preview"
|
||||||
android:contentDescription="@string/candidate_item_device_image" />
|
android:contentDescription="@string/candidate_item_device_image" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
@ -5,18 +5,27 @@
|
|||||||
android:background="?android:attr/activatedBackgroundIndicator"
|
android:background="?android:attr/activatedBackgroundIndicator"
|
||||||
android:padding="4dp">
|
android:padding="4dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/item_preview"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentStart="false"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:contentDescription="Item preview" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/item_image"
|
android:id="@+id/item_image"
|
||||||
android:layout_width="24dp"
|
android:layout_width="24dp"
|
||||||
android:layout_height="24dp"
|
android:layout_height="24dp"
|
||||||
android:layout_alignParentStart="true"
|
android:layout_below="@+id/item_preview"
|
||||||
android:contentDescription="@string/candidate_item_device_image" />
|
android:contentDescription="@string/candidate_item_device_image" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_centerVertical="true"
|
android:layout_centerVertical="true"
|
||||||
android:layout_toEndOf="@+id/item_image"
|
android:layout_below="@+id/item_preview"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:paddingStart="4dp"
|
android:paddingStart="4dp"
|
||||||
android:paddingEnd="4dp">
|
android:paddingEnd="4dp">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user