From 169cc792222431cd864578ad257696e12323a77b Mon Sep 17 00:00:00 2001 From: simonpoole <simon@poole.ch> Date: Fri, 16 Aug 2024 22:01:51 +0200 Subject: [PATCH] Optionally use hardware rendering on Android 10 and later Starting with Android 10 it seems as if at least most of the issues with hardware rendering in Android have been resolved. This commits re-enables the experimental option to turn it on. Resolves https://github.com/MarcusWolschon/osmeditor4android/issues/308 --- .../docs/help/en/Advanced preferences.md | 2 +- .../assets/help/en/Advanced preferences.html | 2 +- src/main/assets/styles/Color-round-no-mp.xml | 2 +- src/main/assets/styles/Color-round.xml | 2 +- src/main/assets/styles/No-path-patterns.xml | 2 +- src/main/assets/styles/Pen-round.xml | 2 +- src/main/java/de/blau/android/Map.java | 20 +++- .../dialogs/TileSourceDiagnostics.java | 2 +- .../blau/android/layer/data/MapOverlay.java | 95 ++++++++++--------- .../blau/android/layer/tasks/MapOverlay.java | 14 ++- .../prefs/AdvancedPrefEditorFragment.java | 6 +- .../blau/android/tasks/MapRouletteTask.java | 13 ++- src/main/java/de/blau/android/tasks/Note.java | 13 ++- .../java/de/blau/android/tasks/OsmoseBug.java | 18 ++-- src/main/java/de/blau/android/tasks/Task.java | 7 +- src/main/java/de/blau/android/tasks/Todo.java | 13 ++- .../android/views/layers/MapTilesLayer.java | 17 +++- .../android/views/util/MapTileProvider.java | 22 ++++- src/main/res/values/strings.xml | 2 +- 19 files changed, 164 insertions(+), 90 deletions(-) diff --git a/documentation/docs/help/en/Advanced preferences.md b/documentation/docs/help/en/Advanced preferences.md index 1d96294b40..363461daaa 100644 --- a/documentation/docs/help/en/Advanced preferences.md +++ b/documentation/docs/help/en/Advanced preferences.md @@ -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 diff --git a/src/main/assets/help/en/Advanced preferences.html b/src/main/assets/help/en/Advanced preferences.html index 21cd991d05..9b88d8131e 100644 --- a/src/main/assets/help/en/Advanced preferences.html +++ b/src/main/assets/help/en/Advanced preferences.html @@ -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 "new task" mode for property editor</h3> diff --git a/src/main/assets/styles/Color-round-no-mp.xml b/src/main/assets/styles/Color-round-no-mp.xml index 645aed1cf3..916a1ace46 100644 --- a/src/main/assets/styles/Color-round-no-mp.xml +++ b/src/main/assets/styles/Color-round-no-mp.xml @@ -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" /> diff --git a/src/main/assets/styles/Color-round.xml b/src/main/assets/styles/Color-round.xml index dcab5ac43d..20a64acac0 100644 --- a/src/main/assets/styles/Color-round.xml +++ b/src/main/assets/styles/Color-round.xml @@ -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" /> diff --git a/src/main/assets/styles/No-path-patterns.xml b/src/main/assets/styles/No-path-patterns.xml index 701d91067a..ce14f25945 100644 --- a/src/main/assets/styles/No-path-patterns.xml +++ b/src/main/assets/styles/No-path-patterns.xml @@ -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" /> diff --git a/src/main/assets/styles/Pen-round.xml b/src/main/assets/styles/Pen-round.xml index 93b8d2d35d..dcde98b697 100644 --- a/src/main/assets/styles/Pen-round.xml +++ b/src/main/assets/styles/Pen-round.xml @@ -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" /> diff --git a/src/main/java/de/blau/android/Map.java b/src/main/java/de/blau/android/Map.java index c031fc93a4..1c99e1b4bb 100755 --- a/src/main/java/de/blau/android/Map.java +++ b/src/main/java/de/blau/android/Map.java @@ -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 * @@ -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); } /** @@ -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; @@ -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); } @@ -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; + } } \ No newline at end of file diff --git a/src/main/java/de/blau/android/dialogs/TileSourceDiagnostics.java b/src/main/java/de/blau/android/dialogs/TileSourceDiagnostics.java index 6ae319fa31..6a424f6133 100644 --- a/src/main/java/de/blau/android/dialogs/TileSourceDiagnostics.java +++ b/src/main/java/de/blau/android/dialogs/TileSourceDiagnostics.java @@ -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); diff --git a/src/main/java/de/blau/android/layer/data/MapOverlay.java b/src/main/java/de/blau/android/layer/data/MapOverlay.java index 17555005e8..f020f28014 100644 --- a/src/main/java/de/blau/android/layer/data/MapOverlay.java +++ b/src/main/java/de/blau/android/layer/data/MapOverlay.java @@ -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(); @@ -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) { @@ -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); @@ -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); + } } } @@ -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; } diff --git a/src/main/java/de/blau/android/layer/tasks/MapOverlay.java b/src/main/java/de/blau/android/layer/tasks/MapOverlay.java index e481ab3e31..61ff5e62c4 100644 --- a/src/main/java/de/blau/android/layer/tasks/MapOverlay.java +++ b/src/main/java/de/blau/android/layer/tasks/MapOverlay.java @@ -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; @@ -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; @@ -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 diff --git a/src/main/java/de/blau/android/prefs/AdvancedPrefEditorFragment.java b/src/main/java/de/blau/android/prefs/AdvancedPrefEditorFragment.java index 5f8225ccce..0c7abd3012 100644 --- a/src/main/java/de/blau/android/prefs/AdvancedPrefEditorFragment.java +++ b/src/main/java/de/blau/android/prefs/AdvancedPrefEditorFragment.java @@ -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; @@ -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; @@ -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(); } diff --git a/src/main/java/de/blau/android/tasks/MapRouletteTask.java b/src/main/java/de/blau/android/tasks/MapRouletteTask.java index 7e389c1d28..c113952c23 100644 --- a/src/main/java/de/blau/android/tasks/MapRouletteTask.java +++ b/src/main/java/de/blau/android/tasks/MapRouletteTask.java @@ -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 diff --git a/src/main/java/de/blau/android/tasks/Note.java b/src/main/java/de/blau/android/tasks/Note.java index 33978c0e22..6f34af2071 100644 --- a/src/main/java/de/blau/android/tasks/Note.java +++ b/src/main/java/de/blau/android/tasks/Note.java @@ -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); } /** diff --git a/src/main/java/de/blau/android/tasks/OsmoseBug.java b/src/main/java/de/blau/android/tasks/OsmoseBug.java index f9a4e21b97..8ef023e42a 100644 --- a/src/main/java/de/blau/android/tasks/OsmoseBug.java +++ b/src/main/java/de/blau/android/tasks/OsmoseBug.java @@ -1,5 +1,7 @@ package de.blau.android.tasks; +import static de.blau.android.contract.Constants.LOG_TAG_LEN; + import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -27,7 +29,8 @@ public final class OsmoseBug extends Bug implements Serializable { private static final long serialVersionUID = 5L; - private static final String DEBUG_TAG = OsmoseBug.class.getSimpleName().substring(0, Math.min(23, OsmoseBug.class.getSimpleName().length())); + private static final int TAG_LEN = Math.min(LOG_TAG_LEN, OsmoseBug.class.getSimpleName().length()); + private static final String DEBUG_TAG = OsmoseBug.class.getSimpleName().substring(0, TAG_LEN); private static final String OSMOSE_ISSUES = "issues"; private static final String OSMOSE_LAT = "lat"; @@ -56,12 +59,15 @@ public final class OsmoseBug extends Bug implements Serializable { /** * Setup the icon caches + * + * @param context android Context + * @param hwAccelerated true if the Canvas is hw accelerated */ - public static void setupIconCache(Context context) { - cachedIconBugOpen = getIcon(context, R.drawable.bug_open); - cachedIconBugChanged = getIcon(context, R.drawable.bug_changed); - cachedIconChangedBugClosed = getIcon(context, R.drawable.bug_changed_closed); - cachedIconBugClosed = getIcon(context, R.drawable.bug_closed); + public static void setupIconCache(@NonNull Context context, boolean hwAccelerated) { + cachedIconBugOpen = getIcon(context, R.drawable.bug_open, hwAccelerated); + cachedIconBugChanged = getIcon(context, R.drawable.bug_changed, hwAccelerated); + cachedIconChangedBugClosed = getIcon(context, R.drawable.bug_changed_closed, hwAccelerated); + cachedIconBugClosed = getIcon(context, R.drawable.bug_closed, hwAccelerated); } /** diff --git a/src/main/java/de/blau/android/tasks/Task.java b/src/main/java/de/blau/android/tasks/Task.java index 64422382f4..829fdec327 100644 --- a/src/main/java/de/blau/android/tasks/Task.java +++ b/src/main/java/de/blau/android/tasks/Task.java @@ -224,12 +224,15 @@ public void setChanged(boolean changed) { * * @param context Android Context * @param icon the icon resource + * @param hwAccelerated true is the canvas is hw accellerated * @return the Bitmap */ @NonNull - static BitmapWithOffset getIcon(@NonNull Context context, int icon) { + static BitmapWithOffset getIcon(@NonNull Context context, int icon, boolean hwAccelerated) { BitmapWithOffset bitmap = new BitmapWithOffset(); - bitmap.icon = BitmapFactory.decodeResource(context.getResources(), icon); + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inPreferredConfig = hwAccelerated ? Bitmap.Config.HARDWARE : Bitmap.Config.ARGB_8888; + bitmap.icon = BitmapFactory.decodeResource(context.getResources(), icon, options); bitmap.w2 = bitmap.icon.getWidth() / 2f; bitmap.h2 = bitmap.icon.getHeight() / 2f; bitmap.iconSelectedBorder = Density.dpToPx(context, ICON_SELECTED_BORDER); diff --git a/src/main/java/de/blau/android/tasks/Todo.java b/src/main/java/de/blau/android/tasks/Todo.java index f0147f3bad..8340580ea3 100644 --- a/src/main/java/de/blau/android/tasks/Todo.java +++ b/src/main/java/de/blau/android/tasks/Todo.java @@ -67,12 +67,15 @@ public final class Todo extends Bug implements Serializable { /** * Setup the icon caches + * + * @param context android Context + * @param hwAccelerated true if the Canvas is hw accelerated */ - public static void setupIconCache(Context context) { - cachedIconTodoOpen = getIcon(context, R.drawable.todo_open); - cachedIconTogoChanged = getIcon(context, R.drawable.todo_open); - cachedIconTodoChangedClosed = getIcon(context, R.drawable.todo_closed); - cachedIconTodoClosed = getIcon(context, R.drawable.todo_closed); + public static void setupIconCache(@NonNull Context context, boolean hwAccelerated) { + cachedIconTodoOpen = getIcon(context, R.drawable.todo_open, hwAccelerated); + cachedIconTogoChanged = getIcon(context, R.drawable.todo_open, hwAccelerated); + cachedIconTodoChangedClosed = getIcon(context, R.drawable.todo_closed, hwAccelerated); + cachedIconTodoClosed = getIcon(context, R.drawable.todo_closed, hwAccelerated); } /** diff --git a/src/main/java/de/blau/android/views/layers/MapTilesLayer.java b/src/main/java/de/blau/android/views/layers/MapTilesLayer.java index 5e44607614..cf62d4abf6 100644 --- a/src/main/java/de/blau/android/views/layers/MapTilesLayer.java +++ b/src/main/java/de/blau/android/views/layers/MapTilesLayer.java @@ -1,5 +1,7 @@ package de.blau.android.views.layers; +import static de.blau.android.contract.Constants.LOG_TAG_LEN; + import java.io.IOException; import java.util.BitSet; import java.util.Collection; @@ -68,7 +70,8 @@ */ public class MapTilesLayer<T> extends MapViewLayer implements ExtentInterface, LayerInfoInterface, DiscardInterface, AttributionInterface { - private static final String DEBUG_TAG = MapTilesLayer.class.getSimpleName().substring(0, Math.min(23, MapTilesLayer.class.getSimpleName().length())); + private static final int TAG_LEN = Math.min(LOG_TAG_LEN, MapTilesLayer.class.getSimpleName().length()); + private static final String DEBUG_TAG = MapTilesLayer.class.getSimpleName().substring(0, TAG_LEN); /** Define a minimum active area for taps on the tile attribution data. */ private static final int TAPAREA_MIN_WIDTH = 40; @@ -173,6 +176,16 @@ default void postRender(@NonNull Canvas c, int z) { } public static class BitmapTileRenderer implements TileRenderer<Bitmap> { + private final boolean hardwareRenderer; + + /** + * Construct a new renderer + * + * @param hardwareRenderer decode bitmap for hardware rendering if true + */ + public BitmapTileRenderer(boolean hardwareRenderer) { + this.hardwareRenderer = hardwareRenderer; + } @Override public void render(@NonNull Canvas c, @NonNull Bitmap tileBlob, int z, @Nullable Rect fromRect, @NonNull Rect screenRect, @NonNull Paint paint) { @@ -182,7 +195,7 @@ public void render(@NonNull Canvas c, @NonNull Bitmap tileBlob, int z, @Nullable @Override @NonNull public TileDecoder<Bitmap> decoder() { - return new MapTileProvider.BitmapDecoder(); + return new MapTileProvider.BitmapDecoder(hardwareRenderer); } } diff --git a/src/main/java/de/blau/android/views/util/MapTileProvider.java b/src/main/java/de/blau/android/views/util/MapTileProvider.java index 7f2b63ca2f..7968ab6be2 100644 --- a/src/main/java/de/blau/android/views/util/MapTileProvider.java +++ b/src/main/java/de/blau/android/views/util/MapTileProvider.java @@ -1,5 +1,7 @@ package de.blau.android.views.util; +import static de.blau.android.contract.Constants.LOG_TAG_LEN; + import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -46,7 +48,8 @@ public class MapTileProvider<T> { /** * Tag used in debug log-entries. */ - private static final String DEBUG_TAG = MapTileProvider.class.getSimpleName().substring(0, Math.min(23, MapTileProvider.class.getSimpleName().length())); + private static final int TAG_LEN = Math.min(LOG_TAG_LEN, MapTileProvider.class.getSimpleName().length()); + private static final String DEBUG_TAG = MapTileProvider.class.getSimpleName().substring(0, TAG_LEN); private static final int MVT_CACHE_SIZE = 128; @@ -85,17 +88,30 @@ public interface TileDecoder<D> { public static class BitmapDecoder implements TileDecoder<Bitmap> { private BitmapFactory.Options options = new BitmapFactory.Options(); + private boolean hardwareRendering; + + /** + * Construct a new decoder + * + * @param hardwareRendering if true decode for hardware rendering + */ + public BitmapDecoder(boolean hardwareRendering) { + this.hardwareRendering = hardwareRendering; + } + @Override public Bitmap decode(@NonNull byte[] data, boolean small) { - if (small) { + if (hardwareRendering) { + options.inPreferredConfig = Bitmap.Config.HARDWARE; + } else if (small) { options.inPreferredConfig = Bitmap.Config.RGB_565; } else { options.inPreferredConfig = Bitmap.Config.ARGB_8888; } return BitmapFactory.decodeByteArray(data, 0, data.length, options); } - } + // =========================================================== // Constructors // =========================================================== diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 30838ad88c..5c688dbc1c 100755 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -1314,7 +1314,7 @@ <string name="config_enableAntiAliasing_title">Enable anti-aliasing</string> <string name="config_enableAntiAliasing_summary">Makes the lines smoother.</string> <string name="config_enableHwAcceleration_title">Enable hardware acceleration</string> - <string name="config_enableHwAcceleration_summary">Allows use of hardware acceleration if and where supported, currently setting this has no effect.</string> + <string name="config_enableHwAcceleration_summary">Turn on use of hardware rendering on Android 10 and later.</string> <string name="config_maxStrokeWidth_title">Max line width</string> <string name="config_maxStrokeWidth_summary">Do not draw a way thicker than this.</string> <string name="config_maxStrokeWidth_current">%1$d px</string>