aboutsummaryrefslogtreecommitdiffstats
path: root/main/src/cgeo/geocaching/utils/MapUtils.java
blob: 948df777a4af33760e3e1def513e7372b6a22e85 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package cgeo.geocaching.utils;

import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;

import org.apache.commons.lang3.builder.HashCodeBuilder;

import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.util.SparseArray;

import java.util.ArrayList;

public final class MapUtils {

    // data for overlays
    private static final int[][] INSET_RELIABLE = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }; // center, 33x40 / 45x51 / 60x68
    private static final int[][] INSET_TYPE = { { 5, 8, 6, 10 }, { 4, 4, 5, 11 }, { 4, 4, 5, 11 } }; // center, 22x22 / 36x36
    private static final int[][] INSET_OWN = { { 21, 0, 0, 26 }, { 25, 0, 0, 35 }, { 40, 0, 0, 48 } }; // top right, 12x12 / 16x16 / 20x20
    private static final int[][] INSET_FOUND = { { 0, 0, 21, 28 }, { 0, 0, 25, 35 }, { 0, 0, 40, 48 } }; // top left, 12x12 / 16x16 / 20x20
    private static final int[][] INSET_USERMODIFIEDCOORDS = { { 21, 28, 0, 0 }, { 19, 25, 0, 0 }, { 25, 33, 0, 0 } }; // bottom right, 12x12 / 26x26 / 35x35
    private static final int[][] INSET_PERSONALNOTE = { { 0, 28, 21, 0 }, { 0, 25, 19, 0 }, { 0, 33, 25, 0 } }; // bottom left, 12x12 / 26x26 / 35x35

    private static final SparseArray<LayerDrawable> overlaysCache = new SparseArray<>();

    private MapUtils() {
        // Do not instantiate
    }

    /**
     * Build the drawable for a given cache.
     *
     * @param res the resources to use
     * @param cache the cache to build the drawable for
     * @return a drawable representing the current cache status
     */
    public static LayerDrawable getCacheItem(final Resources res, final Geocache cache) {
        final int hashcode = new HashCodeBuilder()
                .append(cache.isReliableLatLon())
                .append(cache.getType().id)
                .append(cache.isDisabled() || cache.isArchived())
                .append(cache.getMapMarkerId())
                .append(cache.isOwner())
                .append(cache.isFound())
                .append(cache.hasUserModifiedCoords())
                .append(cache.getPersonalNote())
                .append(cache.isLogOffline())
                .append(cache.getListId() > 0)
                .toHashCode();

        synchronized (overlaysCache) {
            LayerDrawable drawable = overlaysCache.get(hashcode);
            if (drawable == null) {
                drawable = MapUtils.createCacheItem(res, cache);
                overlaysCache.put(hashcode, drawable);
            }
            return drawable;
        }
    }

    /**
     * Clear the cache of drawable items.
     */
    public static void clearCachedItems() {
        synchronized (overlaysCache) {
            overlaysCache.clear();
        }
    }

    private static LayerDrawable createCacheItem(final Resources res, final Geocache cache) {
        // Set initial capacities to the maximum of layers and insets to avoid dynamic reallocation
        final ArrayList<Drawable> layers = new ArrayList<>(9);
        final ArrayList<int[]> insets = new ArrayList<>(8);

        // background: disabled or not
        final Drawable marker = res.getDrawable(cache.getMapMarkerId());
        layers.add(marker);
        final int resolution = marker.getIntrinsicWidth() > 40 ? (marker.getIntrinsicWidth() > 50 ? 2 : 1) : 0;
        // reliable or not
        if (!cache.isReliableLatLon()) {
            insets.add(INSET_RELIABLE[resolution]);
            layers.add(res.getDrawable(R.drawable.marker_notreliable));
        }
        // cache type
        layers.add(res.getDrawable(cache.getType().markerId));
        insets.add(INSET_TYPE[resolution]);
        // own
        if (cache.isOwner()) {
            layers.add(res.getDrawable(R.drawable.marker_own));
            insets.add(INSET_OWN[resolution]);
            // if not, checked if stored
        } else if (cache.getListId() > 0) {
            layers.add(res.getDrawable(R.drawable.marker_stored));
            insets.add(INSET_OWN[resolution]);
        }
        // found
        if (cache.isFound()) {
            layers.add(res.getDrawable(R.drawable.marker_found));
            insets.add(INSET_FOUND[resolution]);
            // if not, perhaps logged offline
        } else if (cache.isLogOffline()) {
            layers.add(res.getDrawable(R.drawable.marker_found_offline));
            insets.add(INSET_FOUND[resolution]);
        }
        // user modified coords
        if (cache.hasUserModifiedCoords()) {
            layers.add(res.getDrawable(R.drawable.marker_usermodifiedcoords));
            insets.add(INSET_USERMODIFIEDCOORDS[resolution]);
        }
        // personal note
        if (cache.getPersonalNote() != null) {
            layers.add(res.getDrawable(R.drawable.marker_personalnote));
            insets.add(INSET_PERSONALNOTE[resolution]);
        }

        final LayerDrawable ld = new LayerDrawable(layers.toArray(new Drawable[layers.size()]));

        int index = 1;
        for (final int[] inset : insets) {
            ld.setLayerInset(index++, inset[0], inset[1], inset[2], inset[3]);
        }

        return ld;
    }
}