Skip to content

Most visited

Recently visited

navigation
XYZTouristAttractions / Shared / src / com.example.android.xyztouristattractions.common /

Utils.java

1
/*
2
 * Copyright 2015 Google Inc. All rights reserved.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
 
17
package com.example.android.xyztouristattractions.common;
18
 
19
import android.Manifest;
20
import android.content.Context;
21
import android.content.SharedPreferences;
22
import android.content.pm.PackageManager;
23
import android.graphics.Bitmap;
24
import android.graphics.BitmapFactory;
25
import android.graphics.Point;
26
import android.graphics.Rect;
27
import android.preference.PreferenceManager;
28
import android.support.v4.content.ContextCompat;
29
import android.util.Log;
30
import android.view.Display;
31
 
32
import com.google.android.gms.common.api.GoogleApiClient;
33
import com.google.android.gms.maps.model.LatLng;
34
import com.google.android.gms.wearable.Asset;
35
import com.google.android.gms.wearable.Node;
36
import com.google.android.gms.wearable.NodeApi;
37
import com.google.android.gms.wearable.Wearable;
38
import com.google.maps.android.SphericalUtil;
39
 
40
import java.io.ByteArrayOutputStream;
41
import java.io.InputStream;
42
import java.text.NumberFormat;
43
import java.util.Collection;
44
import java.util.HashSet;
45
 
46
/**
47
 * This class contains shared static utility methods that both the mobile and
48
 * wearable apps can use.
49
 */
50
public class Utils {
51
    private static final String TAG = Utils.class.getSimpleName();
52
 
53
    private static final String PREFERENCES_LAT = "lat";
54
    private static final String PREFERENCES_LNG = "lng";
55
    private static final String PREFERENCES_GEOFENCE_ENABLED = "geofence";
56
    private static final String DISTANCE_KM_POSTFIX = "km";
57
    private static final String DISTANCE_M_POSTFIX = "m";
58
 
59
    /**
60
     * Check if the app has access to fine location permission. On pre-M
61
     * devices this will always return true.
62
     */
63
    public static boolean checkFineLocationPermission(Context context) {
64
        return PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(
65
                context, Manifest.permission.ACCESS_FINE_LOCATION);
66
    }
67
 
68
    /**
69
     * Calculate distance between two LatLng points and format it nicely for
70
     * display. As this is a sample, it only statically supports metric units.
71
     * A production app should check locale and support the correct units.
72
     */
73
    public static String formatDistanceBetween(LatLng point1, LatLng point2) {
74
        if (point1 == null || point2 == null) {
75
            return null;
76
        }
77
 
78
        NumberFormat numberFormat = NumberFormat.getNumberInstance();
79
        double distance = Math.round(SphericalUtil.computeDistanceBetween(point1, point2));
80
 
81
        // Adjust to KM if M goes over 1000 (see javadoc of method for note
82
        // on only supporting metric)
83
        if (distance >= 1000) {
84
            numberFormat.setMaximumFractionDigits(1);
85
            return numberFormat.format(distance / 1000) + DISTANCE_KM_POSTFIX;
86
        }
87
        return numberFormat.format(distance) + DISTANCE_M_POSTFIX;
88
    }
89
 
90
    /**
91
     * Store the location in the app preferences.
92
     */
93
    public static void storeLocation(Context context, LatLng location) {
94
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
95
        SharedPreferences.Editor editor = prefs.edit();
96
        editor.putLong(PREFERENCES_LAT, Double.doubleToRawLongBits(location.latitude));
97
        editor.putLong(PREFERENCES_LNG, Double.doubleToRawLongBits(location.longitude));
98
        editor.apply();
99
    }
100
 
101
    /**
102
     * Fetch the location from app preferences.
103
     */
104
    public static LatLng getLocation(Context context) {
105
        if (!checkFineLocationPermission(context)) {
106
            return null;
107
        }
108
 
109
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
110
        Long lat = prefs.getLong(PREFERENCES_LAT, Long.MAX_VALUE);
111
        Long lng = prefs.getLong(PREFERENCES_LNG, Long.MAX_VALUE);
112
        if (lat != Long.MAX_VALUE && lng != Long.MAX_VALUE) {
113
            Double latDbl = Double.longBitsToDouble(lat);
114
            Double lngDbl = Double.longBitsToDouble(lng);
115
            return new LatLng(latDbl, lngDbl);
116
        }
117
        return null;
118
    }
119
 
120
    /**
121
     * Store if geofencing triggers will show a notification in app preferences.
122
     */
123
    public static void storeGeofenceEnabled(Context context, boolean enable) {
124
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
125
        SharedPreferences.Editor editor = prefs.edit();
126
        editor.putBoolean(PREFERENCES_GEOFENCE_ENABLED, enable);
127
        editor.apply();
128
    }
129
 
130
    /**
131
     * Retrieve if geofencing triggers should show a notification from app preferences.
132
     */
133
    public static boolean getGeofenceEnabled(Context context) {
134
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
135
        return prefs.getBoolean(PREFERENCES_GEOFENCE_ENABLED, true);
136
    }
137
 
138
    /**
139
     * Convert an asset into a bitmap object synchronously. Only call this
140
     * method from a background thread (it should never be called from the
141
     * main/UI thread as it blocks).
142
     */
143
    public static Bitmap loadBitmapFromAsset(GoogleApiClient googleApiClient, Asset asset) {
144
        if (asset == null) {
145
            throw new IllegalArgumentException("Asset must be non-null");
146
        }
147
        // convert asset into a file descriptor and block until it's ready
148
        InputStream assetInputStream = Wearable.DataApi.getFdForAsset(
149
                googleApiClient, asset).await().getInputStream();
150
 
151
        if (assetInputStream == null) {
152
            Log.w(TAG, "Requested an unknown Asset.");
153
            return null;
154
        }
155
        // decode the stream into a bitmap
156
        return BitmapFactory.decodeStream(assetInputStream);
157
    }
158
 
159
    /**
160
     * Create a wearable asset from a bitmap.
161
     */
162
    public static Asset createAssetFromBitmap(Bitmap bitmap) {
163
        if (bitmap != null) {
164
            final ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
165
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteStream);
166
            return Asset.createFromBytes(byteStream.toByteArray());
167
        }
168
        return null;
169
    }
170
 
171
    /**
172
     * Get a list of all wearable nodes that are connected synchronously.
173
     * Only call this method from a background thread (it should never be
174
     * called from the main/UI thread as it blocks).
175
     */
176
    public static Collection<String> getNodes(GoogleApiClient client) {
177
        Collection<String> results= new HashSet<String>();
178
        NodeApi.GetConnectedNodesResult nodes =
179
                Wearable.NodeApi.getConnectedNodes(client).await();
180
        for (Node node : nodes.getNodes()) {
181
            results.add(node.getId());
182
        }
183
        return results;
184
    }
185
 
186
    /**
187
     * Calculates the square insets on a round device. If the system insets are not set
188
     * (set to 0) then the inner square of the circle is applied instead.
189
     *
190
     * @param display device default display
191
     * @param systemInsets the system insets
192
     * @return adjusted square insets for use on a round device
193
     */
194
    public static Rect calculateBottomInsetsOnRoundDevice(Display display, Rect systemInsets) {
195
        Point size = new Point();
196
        display.getSize(size);
197
        int width = size.x + systemInsets.left + systemInsets.right;
198
        int height = size.y + systemInsets.top + systemInsets.bottom;
199
 
200
        // Minimum inset to use on a round screen, calculated as a fixed percent of screen height
201
        int minInset = (int) (height * Constants.WEAR_ROUND_MIN_INSET_PERCENT);
202
 
203
        // Use system inset if it is larger than min inset, otherwise use min inset
204
        int bottomInset = systemInsets.bottom > minInset ? systemInsets.bottom : minInset;
205
 
206
        // Calculate left and right insets based on bottom inset
207
        double radius = width / 2;
208
        double apothem = radius - bottomInset;
209
        double chord = Math.sqrt(Math.pow(radius, 2) - Math.pow(apothem, 2)) * 2;
210
        int leftRightInset = (int) ((width - chord) / 2);
211
 
212
        Log.d(TAG, "calculateBottomInsetsOnRoundDevice: " + bottomInset + ", " + leftRightInset);
213
 
214
        return new Rect(leftRightInset, 0, leftRightInset, bottomInset);
215
    }
216
}
This site uses cookies to store your preferences for site-specific language and display options.

Hooray!