1
+ /**
2
+ * Modified MIT License
3
+ * <p>
4
+ * Copyright 2020 OneSignal
5
+ * <p>
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ * <p>
13
+ * 1. The above copyright notice and this permission notice shall be included in
14
+ * all copies or substantial portions of the Software.
15
+ * <p>
16
+ * 2. All copies of substantial portions of the Software may only be used in connection
17
+ * with services provided by OneSignal.
18
+ * <p>
19
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
+ * THE SOFTWARE.
26
+ */
27
+
28
+ package com .onesignal ;
29
+
30
+ import android .location .Location ;
31
+ import android .os .Bundle ;
32
+ import android .support .annotation .NonNull ;
33
+
34
+ import com .google .android .gms .common .ConnectionResult ;
35
+ import com .google .android .gms .common .api .GoogleApiClient ;
36
+ import com .google .android .gms .location .LocationListener ;
37
+ import com .google .android .gms .location .LocationRequest ;
38
+ import com .google .android .gms .location .LocationServices ;
39
+
40
+ class GMSLocationController extends LocationController {
41
+
42
+ static final int API_FALLBACK_TIME = 30_000 ;
43
+
44
+ private static GoogleApiClientCompatProxy googleApiClient ;
45
+ static LocationUpdateListener locationUpdateListener ;
46
+
47
+ // Started from this class or PermissionActivity
48
+ static void startGetLocation () {
49
+ initGoogleLocation ();
50
+ }
51
+
52
+ private static void initGoogleLocation () {
53
+ // Prevents overlapping requests
54
+ if (fallbackFailThread != null )
55
+ return ;
56
+
57
+ synchronized (syncLock ) {
58
+ startFallBackThread ();
59
+
60
+ if (googleApiClient == null || lastLocation == null ) {
61
+ GoogleApiClientListener googleApiClientListener = new GoogleApiClientListener ();
62
+ GoogleApiClient googleApiClient = new GoogleApiClient .Builder (classContext )
63
+ .addApi (LocationServices .API )
64
+ .addConnectionCallbacks (googleApiClientListener )
65
+ .addOnConnectionFailedListener (googleApiClientListener )
66
+ .setHandler (locationHandlerThread .mHandler )
67
+ .build ();
68
+
69
+ GMSLocationController .googleApiClient = new GoogleApiClientCompatProxy (googleApiClient );
70
+ GMSLocationController .googleApiClient .connect ();
71
+ } else if (lastLocation != null )
72
+ fireCompleteForLocation (lastLocation );
73
+ }
74
+ }
75
+
76
+ private static int getApiFallbackWait () {
77
+ return API_FALLBACK_TIME ;
78
+ }
79
+
80
+ private static void startFallBackThread () {
81
+ fallbackFailThread = new Thread (new Runnable () {
82
+ public void run () {
83
+ try {
84
+ Thread .sleep (getApiFallbackWait ());
85
+ OneSignal .Log (OneSignal .LOG_LEVEL .WARN , "Location permission exists but GoogleApiClient timed out. Maybe related to mismatch google-play aar versions." );
86
+ LocationController .fireFailedComplete ();
87
+ scheduleUpdate (classContext );
88
+ } catch (InterruptedException e ) {
89
+ // Interruptions expected when connection is made to the api
90
+ }
91
+ }
92
+ }, "OS_GMS_LOCATION_FALLBACK" );
93
+ fallbackFailThread .start ();
94
+ }
95
+
96
+ static void fireFailedComplete () {
97
+ synchronized (syncLock ) {
98
+ if (googleApiClient != null )
99
+ googleApiClient .disconnect ();
100
+ googleApiClient = null ;
101
+ }
102
+ }
103
+
104
+ static void onFocusChange () {
105
+ synchronized (syncLock ) {
106
+ OneSignal .Log (OneSignal .LOG_LEVEL .DEBUG , "GMSLocationController onFocusChange!" );
107
+ // Google location not initialized or connected yet
108
+ if (googleApiClient == null || !googleApiClient .realInstance ().isConnected ())
109
+ return ;
110
+
111
+ if (googleApiClient != null ) {
112
+ GoogleApiClient googleApiClient = GMSLocationController .googleApiClient .realInstance ();
113
+ if (locationUpdateListener != null )
114
+ LocationServices .FusedLocationApi .removeLocationUpdates (googleApiClient , locationUpdateListener );
115
+ locationUpdateListener = new LocationUpdateListener (googleApiClient );
116
+ }
117
+ }
118
+ }
119
+
120
+ private static class GoogleApiClientListener implements GoogleApiClient .ConnectionCallbacks , GoogleApiClient .OnConnectionFailedListener {
121
+ @ Override
122
+ public void onConnected (Bundle bundle ) {
123
+ synchronized (syncLock ) {
124
+ PermissionsActivity .answered = false ;
125
+
126
+ if (googleApiClient == null || googleApiClient .realInstance () == null )
127
+ return ;
128
+
129
+ OneSignal .Log (OneSignal .LOG_LEVEL .DEBUG , "LocationController GoogleApiClientListener onConnected lastLocation: " + lastLocation );
130
+ if (lastLocation == null ) {
131
+ lastLocation = FusedLocationApiWrapper .getLastLocation (googleApiClient .realInstance ());
132
+ OneSignal .Log (OneSignal .LOG_LEVEL .DEBUG , "LocationController GoogleApiClientListener lastLocation: " + lastLocation );
133
+ if (lastLocation != null )
134
+ fireCompleteForLocation (lastLocation );
135
+ }
136
+
137
+ locationUpdateListener = new LocationUpdateListener (googleApiClient .realInstance ());
138
+ }
139
+ }
140
+
141
+ @ Override
142
+ public void onConnectionSuspended (int i ) {
143
+ fireFailedComplete ();
144
+ }
145
+
146
+ @ Override
147
+ public void onConnectionFailed (@ NonNull ConnectionResult connectionResult ) {
148
+ fireFailedComplete ();
149
+ }
150
+ }
151
+
152
+ static class LocationUpdateListener implements LocationListener {
153
+
154
+ private GoogleApiClient googleApiClient ;
155
+
156
+ // this initializer method is already synchronized from LocationController with respect to the GoogleApiClient lock
157
+ LocationUpdateListener (GoogleApiClient googleApiClient ) {
158
+ this .googleApiClient = googleApiClient ;
159
+ init ();
160
+ }
161
+
162
+ private void init () {
163
+ long updateInterval = BACKGROUND_UPDATE_TIME_MS ;
164
+ if (OneSignal .isForeground ())
165
+ updateInterval = FOREGROUND_UPDATE_TIME_MS ;
166
+
167
+ if (googleApiClient != null ) {
168
+ LocationRequest locationRequest = LocationRequest .create ()
169
+ .setFastestInterval (updateInterval )
170
+ .setInterval (updateInterval )
171
+ .setMaxWaitTime ((long ) (updateInterval * 1.5 ))
172
+ .setPriority (LocationRequest .PRIORITY_BALANCED_POWER_ACCURACY );
173
+
174
+ OneSignal .Log (OneSignal .LOG_LEVEL .DEBUG , "GMSLocationController GoogleApiClient requestLocationUpdates!" );
175
+ FusedLocationApiWrapper .requestLocationUpdates (googleApiClient , locationRequest , this );
176
+ }
177
+ }
178
+
179
+ @ Override
180
+ public void onLocationChanged (Location location ) {
181
+ OneSignal .Log (OneSignal .LOG_LEVEL .DEBUG , "GMSLocationController onLocationChanged: " + location );
182
+ lastLocation = location ;
183
+ }
184
+ }
185
+
186
+ static class FusedLocationApiWrapper {
187
+ @ SuppressWarnings ("MissingPermission" )
188
+ static void requestLocationUpdates (GoogleApiClient googleApiClient , LocationRequest locationRequest , LocationListener locationListener ) {
189
+ try {
190
+ synchronized (GMSLocationController .syncLock ) {
191
+ if (googleApiClient .isConnected ())
192
+ LocationServices .FusedLocationApi .requestLocationUpdates (googleApiClient , locationRequest , locationListener );
193
+ }
194
+ } catch (Throwable t ) {
195
+ OneSignal .Log (OneSignal .LOG_LEVEL .WARN , "FusedLocationApi.requestLocationUpdates failed!" , t );
196
+ }
197
+ }
198
+
199
+ @ SuppressWarnings ("MissingPermission" )
200
+ static Location getLastLocation (GoogleApiClient googleApiClient ) {
201
+ synchronized (GMSLocationController .syncLock ) {
202
+ if (googleApiClient .isConnected ())
203
+ return LocationServices .FusedLocationApi .getLastLocation (googleApiClient );
204
+ }
205
+ return null ;
206
+ }
207
+ }
208
+ }
0 commit comments