-
Notifications
You must be signed in to change notification settings - Fork 187
/
Copy pathDispatcherLocationProvider.java
248 lines (209 loc) · 9.89 KB
/
DispatcherLocationProvider.java
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
package com.yayandroid.locationmanager.providers.locationprovider;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import androidx.annotation.NonNull;
import com.google.android.gms.common.ConnectionResult;
import com.yayandroid.locationmanager.constants.FailType;
import com.yayandroid.locationmanager.constants.RequestCode;
import com.yayandroid.locationmanager.helper.LogUtils;
import com.yayandroid.locationmanager.helper.continuoustask.ContinuousTask.ContinuousTaskRunner;
import com.yayandroid.locationmanager.listener.FallbackListener;
public class DispatcherLocationProvider extends LocationProvider implements ContinuousTaskRunner, FallbackListener {
private Dialog gpServicesDialog;
private LocationProvider activeProvider;
private DispatcherLocationSource dispatcherLocationSource;
@Override
public void onPause() {
super.onPause();
if (activeProvider != null) {
activeProvider.onPause();
}
getSourceProvider().gpServicesSwitchTask().pause();
}
@Override
public void onResume() {
super.onResume();
if (activeProvider != null) {
activeProvider.onResume();
}
getSourceProvider().gpServicesSwitchTask().resume();
}
@Override
public void onDestroy() {
super.onDestroy();
if (activeProvider != null) {
activeProvider.onDestroy();
}
getSourceProvider().gpServicesSwitchTask().stop();
dispatcherLocationSource = null;
gpServicesDialog = null;
}
@Override
public void cancel() {
if (activeProvider != null) {
activeProvider.cancel();
}
getSourceProvider().gpServicesSwitchTask().stop();
}
@Override
public boolean isWaiting() {
return activeProvider != null && activeProvider.isWaiting();
}
@Override
public boolean isDialogShowing() {
boolean gpServicesDialogShown = gpServicesDialog != null && gpServicesDialog.isShowing();
boolean anyProviderDialogShown = activeProvider != null && activeProvider.isDialogShowing();
return gpServicesDialogShown || anyProviderDialogShown;
}
@Override
public void runScheduledTask(@NonNull String taskId) {
if (taskId.equals(DispatcherLocationSource.GOOGLE_PLAY_SERVICE_SWITCH_TASK)) {
if (activeProvider instanceof GooglePlayServicesLocationProvider && activeProvider.isWaiting()) {
LogUtils.logI("We couldn't receive location from GooglePlayServices, so switching default providers...");
cancel();
continueWithDefaultProviders();
}
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == RequestCode.GOOGLE_PLAY_SERVICES) {
// Check whether do we have gpServices now or still not!
checkGooglePlayServicesAvailability(false);
} else {
if (activeProvider != null) {
activeProvider.onActivityResult(requestCode, resultCode, data);
}
}
}
@Override
public void get() {
if (getConfiguration().googlePlayServicesConfiguration() != null) {
checkGooglePlayServicesAvailability(true);
} else {
LogUtils.logI("Configuration requires not to use Google Play Services, "
+ "so skipping that step to Default Location Providers");
continueWithDefaultProviders();
}
}
@Override
public void onFallback() {
// This is called from GooglePlayServicesLocationProvider when it fails to before its scheduled time
cancel();
continueWithDefaultProviders();
}
void checkGooglePlayServicesAvailability(boolean askForGooglePlayServices) {
int gpServicesAvailability = getSourceProvider().isGoogleApiAvailable(getContext());
if (gpServicesAvailability == ConnectionResult.SUCCESS) {
LogUtils.logI("GooglePlayServices is available on device.");
getLocationFromGooglePlayServices();
} else {
LogUtils.logI("GooglePlayServices is NOT available on device.");
if (askForGooglePlayServices) {
askForGooglePlayServices(gpServicesAvailability);
} else {
LogUtils.logI("GooglePlayServices is NOT available and even though we ask user to handle error, "
+ "it is still NOT available.");
// This means get method is called by onActivityResult
// which we already ask user to handle with gpServices error
continueWithDefaultProviders();
}
}
}
void askForGooglePlayServices(int gpServicesAvailability) {
if (getConfiguration().googlePlayServicesConfiguration().askForGooglePlayServices() &&
getSourceProvider().isGoogleApiErrorUserResolvable(gpServicesAvailability)) {
resolveGooglePlayServices(gpServicesAvailability);
} else {
LogUtils.logI("Either GooglePlayServices error is not resolvable "
+ "or the configuration doesn't wants us to bother user.");
continueWithDefaultProviders();
}
}
/**
* Handle GooglePlayServices error. Try showing a dialog that maybe can fix the error by user action.
* If error cannot be resolved or user cancelled dialog or dialog cannot be displayed, then {@link #continueWithDefaultProviders()} is called.
* <p>
* The {@link com.google.android.gms.common.GoogleApiAvailability#isGooglePlayServicesAvailable(android.content.Context)} returns one of following in {@link ConnectionResult}:
* SUCCESS, SERVICE_MISSING, SERVICE_UPDATING, SERVICE_VERSION_UPDATE_REQUIRED, SERVICE_DISABLED, SERVICE_INVALID.
* <p>
* See https://developers.google.com/android/reference/com/google/android/gms/common/GoogleApiAvailability#public-int-isgoogleplayservicesavailable-context-context
*/
void resolveGooglePlayServices(int gpServicesAvailability) {
LogUtils.logI("Asking user to handle GooglePlayServices error...");
gpServicesDialog = getSourceProvider().getGoogleApiErrorDialog(getActivity(), gpServicesAvailability,
RequestCode.GOOGLE_PLAY_SERVICES, new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
LogUtils.logI("GooglePlayServices error could've been resolved, "
+ "but user canceled it.");
continueWithDefaultProviders();
}
});
if (gpServicesDialog != null) {
/*
The SERVICE_INVALID, SERVICE_UPDATING errors cannot be resolved via user action.
In these cases, when user closes dialog by clicking OK button, OnCancelListener is not called.
So, to handle these errors, we attach a dismiss event listener that calls continueWithDefaultProviders(), when dialog is closed.
*/
switch (gpServicesAvailability) {
// The version of the Google Play services installed on this device is not authentic.
case ConnectionResult.SERVICE_INVALID:
// Google Play service is currently being updated on this device.
case ConnectionResult.SERVICE_UPDATING:
gpServicesDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
LogUtils.logI("GooglePlayServices error could not have been resolved");
continueWithDefaultProviders();
}
});
break;
}
gpServicesDialog.show();
} else {
LogUtils.logI("GooglePlayServices error could've been resolved, but since LocationManager "
+ "is not running on an Activity, dialog cannot be displayed.");
continueWithDefaultProviders();
}
}
void getLocationFromGooglePlayServices() {
LogUtils.logI("Attempting to get location from Google Play Services providers...");
setLocationProvider(getSourceProvider().createGooglePlayServicesLocationProvider(this));
getSourceProvider().gpServicesSwitchTask().delayed(getConfiguration()
.googlePlayServicesConfiguration().googlePlayServicesWaitPeriod());
activeProvider.get();
}
/**
* Called in case of Google Play Services failed to retrieve location,
* or GooglePlayServicesConfiguration doesn't provided by developer
*/
void continueWithDefaultProviders() {
if (getConfiguration().defaultProviderConfiguration() == null) {
LogUtils.logI("Configuration requires not to use default providers, abort!");
if (getListener() != null) {
getListener().onLocationFailed(FailType.GOOGLE_PLAY_SERVICES_NOT_AVAILABLE);
}
} else {
LogUtils.logI("Attempting to get location from default providers...");
setLocationProvider(getSourceProvider().createDefaultLocationProvider());
activeProvider.get();
}
}
void setLocationProvider(LocationProvider provider) {
this.activeProvider = provider;
activeProvider.configure(this);
}
// For test purposes
void setDispatcherLocationSource(DispatcherLocationSource dispatcherLocationSource) {
this.dispatcherLocationSource = dispatcherLocationSource;
}
private DispatcherLocationSource getSourceProvider() {
if (dispatcherLocationSource == null) {
dispatcherLocationSource = new DispatcherLocationSource(this);
}
return dispatcherLocationSource;
}
}