Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optionally use hardware rendering on Android 10 and later #2663

Merged
merged 1 commit into from
Aug 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion documentation/docs/help/en/Advanced preferences.md
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ Enable voice command support: Default: _off_.

### Enable hardware acceleration

Do not use, may cause hangs of the app and other problems.
Turn on use of hardware rendering on Android 10 and later. Default: _off_

### Enable split window property editor

Expand Down
2 changes: 1 addition & 1 deletion src/main/assets/help/en/Advanced preferences.html
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ <h3>Enable JS Console</h3>
<h3>Enable voice commands</h3>
<p>Enable voice command support: Default: <em>off</em>.</p>
<h3>Enable hardware acceleration</h3>
<p>Do not use, may cause hangs of the app and other problems.</p>
<p>Turn on use of hardware rendering on Android 10 and later. Default: <em>off</em></p>
<h3>Enable split window property editor</h3>
<p>Enable displaying the property editor in a separate window if available. Default: <em>off</em></p>
<h3>Use &quot;new task&quot; mode for property editor</h3>
Expand Down
2 changes: 1 addition & 1 deletion src/main/assets/styles/Color-round-no-mp.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
</dash>
</feature>
<!-- Validation -->
<feature type="problem_node" updateWidth="true" widthFactor="2.0" color="ffff00ff" style="STROKE" cap="ROUND" join="MITER" />
<feature type="problem_node" updateWidth="true" widthFactor="2.0" color="ffff00ff" style="FILL" cap="ROUND" join="MITER" />
<feature type="problem_node_tagged" updateWidth="true" widthFactor="1.5" color="ffff00ff" style="FILL" cap="BUTT" join="MITER" />
<feature type="problem_node_thin" updateWidth="false" widthFactor="1.0" color="ffff00ff" style="STROKE" cap="BUTT" join="MITER" strokeWidth="1.0" typefacestyle="0" textsize="12.0" />
<feature type="problem_way" updateWidth="true" widthFactor="1.5" color="ffff00ff" style="STROKE" cap="BUTT" join="MITER" labelKey="name" />
Expand Down
2 changes: 1 addition & 1 deletion src/main/assets/styles/Color-round.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
</dash>
</feature>
<!-- Validation -->
<feature type="problem_node" updateWidth="true" widthFactor="2.0" color="ffff00ff" style="STROKE" cap="ROUND" join="MITER" />
<feature type="problem_node" updateWidth="true" widthFactor="2.0" color="ffff00ff" style="FILL" cap="ROUND" join="MITER" />
<feature type="problem_node_tagged" updateWidth="true" widthFactor="1.5" color="ffff00ff" style="FILL" cap="BUTT" join="MITER" />
<feature type="problem_node_thin" updateWidth="false" widthFactor="1.0" color="ffff00ff" style="STROKE" cap="BUTT" join="MITER" strokeWidth="1.0" typefacestyle="0" textsize="12.0" />
<feature type="problem_way" updateWidth="true" widthFactor="1.5" color="ffff00ff" style="STROKE" cap="BUTT" join="MITER" labelKey="name" />
Expand Down
2 changes: 1 addition & 1 deletion src/main/assets/styles/No-path-patterns.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
</dash>
</feature>
<!-- Validation -->
<feature type="problem_node" updateWidth="true" widthFactor="2.0" color="ffff00ff" style="STROKE" cap="ROUND" join="MITER" />
<feature type="problem_node" updateWidth="true" widthFactor="2.0" color="ffff00ff" style="FILL" cap="ROUND" join="MITER" />
<feature type="problem_node_tagged" updateWidth="true" widthFactor="1.5" color="ffff00ff" style="FILL" cap="BUTT" join="MITER" />
<feature type="problem_node_thin" updateWidth="false" widthFactor="1.0" color="ffff00ff" style="STROKE" cap="BUTT" join="MITER" strokeWidth="1.0" typefacestyle="0" textsize="12.0" />
<feature type="problem_way" updateWidth="true" widthFactor="1.5" color="ffff00ff" style="STROKE" cap="BUTT" join="MITER" labelKey="name" />
Expand Down
2 changes: 1 addition & 1 deletion src/main/assets/styles/Pen-round.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
</dash>
</feature>
<!-- Validation -->
<feature type="problem_node" updateWidth="true" widthFactor="2.0" color="ffff00ff" style="STROKE" cap="ROUND" join="MITER" />
<feature type="problem_node" updateWidth="true" widthFactor="2.0" color="ffff00ff" style="FILL" cap="ROUND" join="MITER" />
<feature type="problem_node_tagged" updateWidth="true" widthFactor="1.5" color="ffff00ff" style="FILL" cap="BUTT" join="MITER" />
<feature type="problem_node_thin" updateWidth="false" widthFactor="1.0" color="ffff00ff" style="STROKE" cap="BUTT" join="MITER" strokeWidth="1.0" typefacestyle="0" textsize="12.0" />
<feature type="problem_way" updateWidth="true" widthFactor="1.5" color="ffff00ff" style="STROKE" cap="BUTT" join="MITER" labelKey="name" />
Expand Down
20 changes: 17 additions & 3 deletions src/main/java/de/blau/android/Map.java
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@ public class Map extends View implements IMapView {

private TrackerService tracker = null;

private final boolean hardwareLayerType;

/**
* Construct a new Map object that orchestrates the layer drawing and related rendering
*
Expand All @@ -192,7 +194,8 @@ public Map(@NonNull final Context context) {

iconRadius = Density.dpToPx(context, ICON_SIZE_DP / 2);

setLayerType(View.LAYER_TYPE_SOFTWARE, null);
hardwareLayerType = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && App.getPreferences(context).hwAccelerationEnabled();
setLayerType(hardwareLayerType ? View.LAYER_TYPE_HARDWARE : View.LAYER_TYPE_SOFTWARE, null);
}

/**
Expand Down Expand Up @@ -225,7 +228,7 @@ public void setUpLayers(@NonNull Context ctx) {
layer = new de.blau.android.layer.mvt.MapOverlay(this, new VectorTileRenderer(), false);
((MapTilesOverlayLayer<?>) layer).setRendererInfo(backgroundSource);
} else {
layer = new MapTilesLayer<Bitmap>(this, backgroundSource, null, new MapTilesLayer.BitmapTileRenderer());
layer = new MapTilesLayer<Bitmap>(this, backgroundSource, null, new MapTilesLayer.BitmapTileRenderer(hardwareLayerType));
}
}
break;
Expand All @@ -235,7 +238,7 @@ public void setUpLayers(@NonNull Context ctx) {
if (overlaySource.getTileType() == TileType.MVT) {
layer = new de.blau.android.layer.mvt.MapOverlay(this, new VectorTileRenderer(), true);
} else {
layer = new MapTilesOverlayLayer<Bitmap>(this, new MapTilesLayer.BitmapTileRenderer());
layer = new MapTilesOverlayLayer<Bitmap>(this, new MapTilesLayer.BitmapTileRenderer(hardwareLayerType));
}
((MapTilesOverlayLayer<?>) layer).setRendererInfo(overlaySource);
}
Expand Down Expand Up @@ -1302,4 +1305,15 @@ public TrackerService getTracker() {
public boolean rtlLayout() {
return getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
}

/**
* Check if we configured hardware acceleration
*
* The value returned from isHardwareAccelerated seems to not necessarily be consistent with what we set
*
* @return true if we enabled hardware acceleration
*/
public boolean isHardwareLayerType() {
return hardwareLayerType;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ protected Void doInBackground(Void param) {
text.setText(tester.getOutput());
byte[] image = tester.getTile();
if (result && tester.getTileType() == TileType.BITMAP && image != null && image.length > 0) {
BitmapDecoder decoder = new BitmapDecoder();
BitmapDecoder decoder = new BitmapDecoder(false);
Bitmap bitmap = decoder.decode(image, false);
if (bitmap != null) {
tileView.setVisibility(View.VISIBLE);
Expand Down
95 changes: 50 additions & 45 deletions src/main/java/de/blau/android/layer/data/MapOverlay.java
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@ protected void onDraw(Canvas canvas, IMapView osmv) {
@SuppressWarnings("unchecked")
private void paintOsmData(@NonNull final Canvas canvas) {

boolean hwAccelarationWorkaround = canvas.isHardwareAccelerated();
boolean hwAccelerated = canvas.isHardwareAccelerated();

int screenWidth = map.getWidth();
int screenHeight = map.getHeight();
Expand Down Expand Up @@ -607,8 +607,7 @@ private void paintOsmData(@NonNull final Canvas canvas) {
coordSize++;
}
}
paintNode(canvas, n, x, y, hwAccelarationWorkaround,
drawTolerance && !noTolerance && (n.getState() != OsmElement.STATE_UNCHANGED || isInDownload(lon, lat)));
paintNode(canvas, n, x, y, hwAccelerated, drawTolerance && !noTolerance && (n.getState() != OsmElement.STATE_UNCHANGED || isInDownload(lon, lat)));
}
// turn restrictions
if (inNodeIconZoomRange && showIcons) {
Expand Down Expand Up @@ -977,10 +976,10 @@ private void paintRestriction(@NonNull final Canvas canvas, int screenWidth, int
* @param node Node to be painted.
* @param x screen x coordinate
* @param y screen y coordinate
* @param hwAccelarationWorkaround use a workaround for unsupported operations when HW acceleration is used
* @param hwAccelerated use a workaround for unsupported operations when HW acceleration is used
* @param drawTolerance draw the touch halo
*/
private void paintNode(@NonNull final Canvas canvas, @NonNull final Node node, final float x, final float y, final boolean hwAccelarationWorkaround,
private void paintNode(@NonNull final Canvas canvas, @NonNull final Node node, final float x, final float y, final boolean hwAccelerated,
final boolean drawTolerance) {

boolean isSelected = tmpDrawingSelectedNodes != null && tmpDrawingSelectedNodes.contains(node);
Expand Down Expand Up @@ -1068,57 +1067,58 @@ private void paintNode(@NonNull final Canvas canvas, @NonNull final Node node, f
isTagged = false;
}

if (isTagged) {
boolean noIcon = true;
if (inNodeIconZoomRange && showIcons) {
Float direction = getDirection(node);
if (direction != null && !direction.equals(Float.NaN)) {
canvas.save();
canvas.rotate(direction + 90, x, y);
canvas.translate(x - iconRadius, y);
canvas.drawPath(currentStyle.getDirectionArrowPath(), nodeFeatureStyle.getPaint());
canvas.restore();
}
if (!isTagged) {
// this bit of code duplication makes sense
if (zoomLevel < featureStyle.getMinVisibleZoom()) {
return;
}
Paint paint = featureStyle.getPaint();
if (hwAccelerated) { // we don't actually know if this is slower than drawPoint
canvas.drawCircle(x, y, paint.getStrokeWidth() / 2, paint);
} else {
canvas.drawPoint(x, y, paint);
}
return;
}

noIcon = tmpPresets == null || !paintNodeIcon(node, canvas, x, y, isSelected || hasProblem ? featureStyleTagged : null);
if (noIcon) {
String houseNumber = node.getTagWithKey(Tags.KEY_ADDR_HOUSENUMBER);
if (houseNumber != null && !"".equals(houseNumber)) { // draw house-numbers
paintHouseNumber(x, y, canvas, featureStyleThin, featureStyleFontSmall, houseNumber);
return;
}
} else if (zoomLevel > showIconLabelZoomLimit) {
paintLabel(x, y, canvas, featureStyleFont, node, nodeFeatureStyleTagged.getPaint().getStrokeWidth(), true);
}
boolean noIcon = true;
if (inNodeIconZoomRange && showIcons) {
Float direction = getDirection(node);
if (direction != null && !direction.equals(Float.NaN)) {
canvas.save();
canvas.rotate(direction + 90, x, y);
canvas.translate(x - iconRadius, y);
canvas.drawPath(currentStyle.getDirectionArrowPath(), nodeFeatureStyle.getPaint());
canvas.restore();
}

noIcon = tmpPresets == null || !paintNodeIcon(node, canvas, x, y, isSelected || hasProblem ? featureStyleTagged : null);
if (noIcon) {
// draw regular nodes or without icons
if (zoomLevel < featureStyleTagged.getMinVisibleZoom()) {
String houseNumber = node.getTagWithKey(Tags.KEY_ADDR_HOUSENUMBER);
if (houseNumber != null && !"".equals(houseNumber)) { // draw house-numbers
paintHouseNumber(x, y, canvas, featureStyleThin, featureStyleFontSmall, houseNumber);
return;
}
Paint paint = featureStyleTagged.getPaint();
float strokeWidth = paint.getStrokeWidth();
if (hwAccelarationWorkaround) {
canvas.drawCircle(x, y, strokeWidth / 2, paint);
} else {
canvas.drawPoint(x, y, paint);
}
if (inNodeIconZoomRange) {
paintLabel(x, y, canvas, featureStyleFont, node, strokeWidth, false);
}
} else if (zoomLevel > showIconLabelZoomLimit) {
paintLabel(x, y, canvas, featureStyleFont, node, nodeFeatureStyleTagged.getPaint().getStrokeWidth(), true);
}
} else {
// this bit of code duplication makes sense
if (zoomLevel < featureStyle.getMinVisibleZoom()) {
}

if (noIcon) {
// draw regular nodes or without icons
if (zoomLevel < featureStyleTagged.getMinVisibleZoom()) {
return;
}
Paint paint = featureStyle.getPaint();
if (hwAccelarationWorkaround) { // FIXME we don't actually know if this is slower than drawPoint
canvas.drawCircle(x, y, paint.getStrokeWidth() / 2, paint);
Paint paint = featureStyleTagged.getPaint();
float strokeWidth = paint.getStrokeWidth();
if (hwAccelerated) {
canvas.drawCircle(x, y, strokeWidth / 2, paint);
} else {
canvas.drawPoint(x, y, paint);
}
if (inNodeIconZoomRange) {
paintLabel(x, y, canvas, featureStyleFont, node, strokeWidth, false);
}
}
}

Expand Down Expand Up @@ -1271,8 +1271,13 @@ private void retrieveIcon(@NonNull OsmElement element, boolean isWay, @NonNull W
}
Bitmap icon;
if (iconDrawable != null) {
icon = Bitmap.createBitmap(iconRadius * 2, iconRadius * 2, Config.ARGB_8888);
icon = Bitmap.createBitmap(iconRadius * 2, iconRadius * 2, Bitmap.Config.ARGB_8888);
iconDrawable.draw(new Canvas(icon));
if (map.isHardwareLayerType()) {
Bitmap temp = icon;
icon = temp.copy(Bitmap.Config.HARDWARE, false);
temp.recycle();
}
} else {
icon = NOICON;
}
Expand Down
14 changes: 9 additions & 5 deletions src/main/java/de/blau/android/layer/tasks/MapOverlay.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package de.blau.android.layer.tasks;

import static de.blau.android.contract.Constants.LOG_TAG_LEN;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
Expand Down Expand Up @@ -59,7 +61,8 @@
public class MapOverlay extends MapViewLayer
implements ExtentInterface, DiscardInterface, ClickableInterface<Task>, LayerInfoInterface, ConfigureInterface, PruneableInterface {

private static final String DEBUG_TAG = MapOverlay.class.getSimpleName().substring(0, Math.min(23, MapOverlay.class.getSimpleName().length()));
private static final int TAG_LEN = Math.min(LOG_TAG_LEN, MapOverlay.class.getSimpleName().length());
private static final String DEBUG_TAG = MapOverlay.class.getSimpleName().substring(0, TAG_LEN);

public static final String FILENAME = "selectedtask" + "." + FileExtensions.RES;

Expand Down Expand Up @@ -120,10 +123,11 @@ public MapOverlay(@NonNull final Map map) {
setPrefs(prefs);
download = new TaskDownloader(prefs.getServer());
// the following sets up the static icon caches
Note.setupIconCache(context);
OsmoseBug.setupIconCache(context);
MapRouletteTask.setupIconCache(context);
Todo.setupIconCache(context);
boolean hwAccelerated = map.isHardwareLayerType();
Note.setupIconCache(context, hwAccelerated);
OsmoseBug.setupIconCache(context, hwAccelerated);
MapRouletteTask.setupIconCache(context, hwAccelerated);
Todo.setupIconCache(context, hwAccelerated);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package de.blau.android.prefs;

import static de.blau.android.contract.Constants.LOG_TAG_LEN;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
Expand All @@ -21,7 +23,8 @@

public class AdvancedPrefEditorFragment extends ExtendedPreferenceFragment {

private static final String DEBUG_TAG = AdvancedPrefEditorFragment.class.getSimpleName().substring(0, Math.min(23, AdvancedPrefEditorFragment.class.getSimpleName().length()));
private static final int TAG_LEN = Math.min(LOG_TAG_LEN, AdvancedPrefEditorFragment.class.getSimpleName().length());
private static final String DEBUG_TAG = AdvancedPrefEditorFragment.class.getSimpleName().substring(0, TAG_LEN);

private Resources r;
AdvancedPrefDatabase db;
Expand Down Expand Up @@ -87,6 +90,7 @@ public void onResume() {
setRestartRequiredMessage(R.string.config_autosaveMaxFiles_key);
setRestartRequiredMessage(R.string.config_indexMediaStore_key);
setRestartRequiredMessage(R.string.config_supportPresetLabels_key);
setRestartRequiredMessage(R.string.config_enableHwAcceleration_key);
setTitle();
}

Expand Down
13 changes: 8 additions & 5 deletions src/main/java/de/blau/android/tasks/MapRouletteTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,15 @@ public class MapRouletteTask extends LongIdTask {

/**
* Setup the icon caches
*
* @param context android Context
* @param hwAccelerated true if the Canvas is hw accelerated
*/
public static void setupIconCache(Context context) {
cachedIconRouletteOpen = getIcon(context, R.drawable.roulette_open);
cachedIconRouletteChanged = getIcon(context, R.drawable.roulette_changed);
cachedIconChangedRouletteClosed = getIcon(context, R.drawable.roulette_closed_changed);
cachedIconRouletteClosed = getIcon(context, R.drawable.roulette_closed);
public static void setupIconCache(@NonNull Context context, boolean hwAccelerated) {
cachedIconRouletteOpen = getIcon(context, R.drawable.roulette_open, hwAccelerated);
cachedIconRouletteChanged = getIcon(context, R.drawable.roulette_changed, hwAccelerated);
cachedIconChangedRouletteClosed = getIcon(context, R.drawable.roulette_closed_changed, hwAccelerated);
cachedIconRouletteClosed = getIcon(context, R.drawable.roulette_closed, hwAccelerated);
}

@Override
Expand Down
13 changes: 8 additions & 5 deletions src/main/java/de/blau/android/tasks/Note.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,15 @@ public Note(XmlPullParser parser) throws XmlPullParserException, IOException, Nu

/**
* Setup the icon caches
*
* @param context android Context
* @param hwAccelerated true if the Canvas is hw accelerated
*/
public static void setupIconCache(Context context) {
cachedIconNoteOpen = getIcon(context, R.drawable.note_open);
cachedIconNoteChanged = getIcon(context, R.drawable.note_changed);
cachedIconNoteChangedClosed = getIcon(context, R.drawable.note_changed_closed);
cachedIconNoteClosed = getIcon(context, R.drawable.note_closed);
public static void setupIconCache(@NonNull Context context, boolean hwAccelerated) {
cachedIconNoteOpen = getIcon(context, R.drawable.note_open, hwAccelerated);
cachedIconNoteChanged = getIcon(context, R.drawable.note_changed, hwAccelerated);
cachedIconNoteChangedClosed = getIcon(context, R.drawable.note_changed_closed, hwAccelerated);
cachedIconNoteClosed = getIcon(context, R.drawable.note_closed, hwAccelerated);
}

/**
Expand Down
Loading
Loading