Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5d290d5

Browse files
committed
#168 Add precise location option for weather glance extension
1 parent 7d9ac17 commit 5d290d5

File tree

17 files changed

+269
-175
lines changed

17 files changed

+269
-175
lines changed

app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
xmlns:tools="http://schemas.android.com/tools">
2020

2121
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
22+
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
2223
<uses-permission android:name="android.permission.ACCESS_HIDDEN_PROFILES" />
2324
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
2425
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

app/src/main/java/com/stario/launcher/activities/launcher/glance/extensions/weather/ForecastAdapter.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,15 @@
3535

3636
import java.text.DateFormat;
3737
import java.text.SimpleDateFormat;
38-
import java.util.ArrayList;
38+
import java.util.List;
3939

4040
public class ForecastAdapter extends RecyclerView.Adapter<ForecastAdapter.ViewHolder> {
4141
private static final int FORECAST_SIZE = 12;
42-
private final ArrayList<Weather.Data> data;
42+
private final List<Weather.Data> data;
4343
private final int indexToStart;
4444
private final SharedPreferences preferences;
4545

46-
public ForecastAdapter(ThemedActivity activity, ArrayList<Weather.Data> data, int indexToStart) {
46+
public ForecastAdapter(ThemedActivity activity, List<Weather.Data> data, int indexToStart) {
4747
this.preferences = activity.getApplicationContext().getSharedPreferences(Entry.STARIO);
4848
this.data = data;
4949
this.indexToStart = indexToStart;

app/src/main/java/com/stario/launcher/activities/launcher/glance/extensions/weather/Weather.java

Lines changed: 90 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
import android.content.Intent;
2424
import android.content.IntentFilter;
2525
import android.content.SharedPreferences;
26+
import android.content.pm.PackageManager;
2627
import android.location.Address;
28+
import android.location.LocationManager;
2729
import android.util.Log;
2830
import android.view.LayoutInflater;
2931
import android.view.View;
@@ -56,20 +58,20 @@
5658
import org.json.JSONException;
5759
import org.json.JSONObject;
5860

59-
import java.io.BufferedInputStream;
60-
import java.io.BufferedReader;
61-
import java.io.InputStream;
62-
import java.io.InputStreamReader;
6361
import java.net.HttpURLConnection;
6462
import java.net.URL;
6563
import java.util.ArrayList;
6664
import java.util.Calendar;
6765
import java.util.Date;
6866
import java.util.HashMap;
67+
import java.util.List;
68+
import java.util.Locale;
69+
import java.util.concurrent.CopyOnWriteArrayList;
6970
import java.util.concurrent.Future;
7071

7172
public class Weather extends GlanceDialogExtension {
7273
public static final String ACTION_REQUEST_UPDATE = "com.stario.REQUEST_UPDATE";
74+
public static final String PRECISE_LOCATION = "com.stario.PRECISE_LOCATION";
7375
public static final String FORECAST_KEY = "com.stario.WEATHER_FORECAST";
7476
public static final String IMPERIAL_KEY = "com.stario.IMPERIAL";
7577
public static final String LOCATION_NAME = "com.stario.LOCATION";
@@ -79,7 +81,8 @@ public class Weather extends GlanceDialogExtension {
7981
private static final String TAG = "com.stario.launcher.Weather";
8082

8183
private static final int FORECAST_MAX_ENTRIES = 20;
82-
private static final int UPDATE_INTERVAL = 3_600_000;
84+
private static final int DEFAULT_UPDATE_INTERVAL = 3_600_000;
85+
private static final int FALLBACK_UPDATE_INTERVAL = 300_000;
8386
private static final int REQUEST_TIMEOUT = 10_000;
8487
private static final int DAY = 0;
8588
private static final int NIGHT = 1;
@@ -337,46 +340,50 @@ void assign(double value) {
337340
}});
338341
}};
339342

340-
private static double lat = Double.MAX_VALUE;
341-
private static double lon = Double.MAX_VALUE;
343+
private static volatile double lat = Double.MAX_VALUE;
344+
private static volatile double lon = Double.MAX_VALUE;
342345

343346
private final BroadcastReceiver receiver;
344347
private final WeatherPreview preview;
345348
private final DateParser dateParser;
346349

347350
private SharedPreferences weatherPreferences;
348-
private ArrayList<Data> weatherData;
349351
private SharedPreferences settings;
352+
private GeocoderFallback geocoder;
353+
private volatile Address address;
354+
private volatile long lastUpdate;
355+
private List<Data> weatherData;
350356
private Future<?> runningTask;
351357
private RecyclerView recycler;
352358
private TextView temperature;
353-
private GeocoderFallback geocoder;
354359
private TextView location;
355360
private TextView summary;
356-
private Address address;
357-
private long lastUpdate;
358361
private View direction;
359362
private TextView speed;
360363
private View container;
361364
private ImageView icon;
362365

363366
public Weather() {
364-
this.weatherData = new ArrayList<>();
367+
this.weatherData = new CopyOnWriteArrayList<>();
365368
this.dateParser = DateParser.newBuilder().build();
366369
this.runningTask = null;
370+
this.address = null;
367371
this.lastUpdate = 0;
368372

369373
this.preview = new WeatherPreview();
370374
this.receiver = new BroadcastReceiver() {
371375
@Override
372376
public void onReceive(Context context, Intent intent) {
373377
lastUpdate = 0;
378+
address = null;
374379
weatherData.clear();
375380
preview.update(null);
376381

377-
if (runningTask != null &&
378-
!runningTask.isDone()) {
379-
runningTask.cancel(true);
382+
synchronized (Weather.this) {
383+
if (runningTask != null &&
384+
!runningTask.isDone()) {
385+
runningTask.cancel(true);
386+
}
380387
}
381388

382389
update();
@@ -468,22 +475,44 @@ protected void updateScaling(@FloatRange(from = 0f, to = 1f) float fraction,
468475
public HashMap<String, Object> data = new HashMap<>();
469476

470477
@Override
471-
public void update() {
478+
public synchronized void update() {
472479
if (!weatherPreferences.getBoolean(FORECAST_KEY, true) ||
473480
(runningTask != null && !runningTask.isDone())) {
474481
return;
475482
}
476483

477484
runningTask = Utils.submitTask(() -> {
478-
if (Math.abs(System.currentTimeMillis() - lastUpdate) > UPDATE_INTERVAL) {
479-
if (weatherPreferences.contains(LATITUDE_KEY) &&
480-
weatherPreferences.contains(LONGITUDE_KEY)) {
481-
lat = Double.longBitsToDouble(
482-
weatherPreferences.getLong(LATITUDE_KEY, Long.MAX_VALUE));
483-
lon = Double.longBitsToDouble(
484-
weatherPreferences.getLong(LONGITUDE_KEY, Long.MAX_VALUE));
485-
} else {
486-
updateLocation(Utils.getPublicIPAddress());
485+
if (Math.abs(System.currentTimeMillis() - lastUpdate) > DEFAULT_UPDATE_INTERVAL) {
486+
boolean prefersPreciseLocation = weatherPreferences.getBoolean(PRECISE_LOCATION, false);
487+
boolean fetchedPreciseLocation = false;
488+
489+
if (prefersPreciseLocation) {
490+
if (activity.checkSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
491+
== PackageManager.PERMISSION_GRANTED) {
492+
LocationManager locationManager = (LocationManager)
493+
activity.getSystemService(Context.LOCATION_SERVICE);
494+
android.location.Location location =
495+
locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
496+
497+
if (location != null) {
498+
lat = location.getLatitude();
499+
lon = location.getLongitude();
500+
501+
fetchedPreciseLocation = true;
502+
}
503+
}
504+
}
505+
506+
if (!fetchedPreciseLocation) {
507+
if (weatherPreferences.contains(LATITUDE_KEY) &&
508+
weatherPreferences.contains(LONGITUDE_KEY)) {
509+
lat = Double.longBitsToDouble(
510+
weatherPreferences.getLong(LATITUDE_KEY, Long.MAX_VALUE));
511+
lon = Double.longBitsToDouble(
512+
weatherPreferences.getLong(LONGITUDE_KEY, Long.MAX_VALUE));
513+
} else {
514+
loadApproximatedLocation(Utils.getPublicIPAddress());
515+
}
487516
}
488517

489518
if (lat < -90 || lat > 90 ||
@@ -537,11 +566,24 @@ public void update() {
537566
int index = getFirstIndexInTime();
538567

539568
if (index > 0) {
540-
UiUtils.runOnUIThread(() ->
541-
preview.update(this.weatherData.get(index)));
569+
UiUtils.runOnUIThread(() -> preview.update(this.weatherData.get(index)));
570+
}
571+
572+
String addressName = weatherPreferences.getString(LOCATION_NAME, null);
573+
if (addressName == null) {
574+
address = geocoder.getFromLocation(lat, lon);
575+
} else {
576+
address = new Address(Locale.ENGLISH);
577+
address.setLocality(addressName);
542578
}
543579

544-
lastUpdate = System.currentTimeMillis();
580+
// Artificially change the update interval if we want precise location data
581+
// But location is not accessible
582+
if(!fetchedPreciseLocation && prefersPreciseLocation) {
583+
lastUpdate = System.currentTimeMillis() - DEFAULT_UPDATE_INTERVAL + FALLBACK_UPDATE_INTERVAL;
584+
} else {
585+
lastUpdate = System.currentTimeMillis();
586+
}
545587
} catch (JSONException exception) {
546588
Log.e(TAG, "updateWeather: ", exception);
547589
}
@@ -566,17 +608,25 @@ private void updateData() {
566608

567609
summary.setText(getSummary(data.iconCode));
568610

569-
String locationString = weatherPreferences.getString(LOCATION_NAME, null);
570-
if (locationString != null) {
571-
location.setText(locationString);
572-
} else if (address != null) {
573-
locationString = address.getSubLocality();
611+
if (address != null) {
612+
String subLocality = address.getSubLocality();
613+
String locality = address.getLocality();
614+
615+
if (locality == null) {
616+
locality = address.getSubAdminArea();
617+
}
618+
619+
if (locality == null) {
620+
locality = address.getAdminArea();
621+
}
574622

575-
if (locationString == null) {
576-
locationString = address.getLocality();
623+
if (locality == null) {
624+
locality = subLocality;
625+
} else if (subLocality != null) {
626+
locality = subLocality + ", " + locality;
577627
}
578628

579-
location.setText(locationString);
629+
location.setText(locality);
580630
} else {
581631
location.setText(null);
582632
}
@@ -653,9 +703,8 @@ public static int getSummary(String iconCode) {
653703
return summary != null ? summary : 0;
654704
}
655705

656-
private void updateLocation(String ip) {
706+
private void loadApproximatedLocation(String ip) {
657707
for (IpApiEntry entry : LOCATION_APIS) {
658-
StringBuilder response = new StringBuilder();
659708
HttpURLConnection connection = null;
660709

661710
try {
@@ -671,22 +720,11 @@ private void updateLocation(String ip) {
671720
connection.connect();
672721

673722
int responseCode = connection.getResponseCode();
674-
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
675-
InputStream inputStream = new BufferedInputStream(connection.getInputStream());
676-
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
677-
678-
String line;
679-
680-
while ((line = reader.readLine()) != null) {
681-
response.append(line);
682-
}
683-
684-
JSONObject jsonObject = new JSONObject(response.toString());
723+
if (responseCode == HttpURLConnection.HTTP_OK) {
724+
JSONObject jsonObject = new JSONObject(Utils.readStream(connection.getInputStream()));
685725
for (IpApiEntry.Callback callback : entry.callback) {
686726
callback.assign(jsonObject.getDouble(callback.field));
687727
}
688-
689-
address = geocoder.getFromLocation(lat, lon);
690728
} else {
691729
Log.w(TAG, "getWeatherInfo: Server returned non-OK status: " + responseCode);
692730
}
@@ -701,7 +739,6 @@ private void updateLocation(String ip) {
701739
}
702740

703741
private JSONObject getWeatherInfo() {
704-
StringBuilder response = new StringBuilder();
705742
HttpURLConnection connection = null;
706743

707744
try {
@@ -726,7 +763,7 @@ private JSONObject getWeatherInfo() {
726763

727764
return null;
728765
} catch (Exception exception) {
729-
Log.e(TAG, "getWeatherInfo: " + exception.getMessage());
766+
Log.e(TAG, "getWeatherInfo: ", exception);
730767

731768
return null;
732769
} finally {

app/src/main/java/com/stario/launcher/activities/settings/Settings.java

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
package com.stario.launcher.activities.settings;
1919

20+
import android.Manifest;
2021
import android.animation.LayoutTransition;
2122
import android.annotation.SuppressLint;
2223
import android.app.Activity;
@@ -470,8 +471,7 @@ public void onClick(View view) {
470471
}
471472
});
472473

473-
locationName.setText(weather.getString(Weather.LOCATION_NAME,
474-
resources.getString(R.string.location_ip_based)));
474+
locationName.setText(getLocationString(weather, resources));
475475
location.setOnClickListener(new View.OnClickListener() {
476476
private LocationDialog dialog;
477477
private boolean showing = false;
@@ -481,11 +481,9 @@ public void onClick(View view) {
481481
if (dialog == null) {
482482
dialog = new LocationDialog(Settings.this);
483483

484-
dialog.setOnDismissListener(dialog -> {
485-
locationName.setText(weather.getString(Weather.LOCATION_NAME,
486-
resources.getString(R.string.location_ip_based)));
487-
showing = false;
488-
});
484+
dialog.setOnLocationUpdateListener(() ->
485+
locationName.setText(getLocationString(weather, resources)));
486+
dialog.setOnDismissListener(dialog -> showing = false);
489487
}
490488

491489
if (!showing) {
@@ -695,6 +693,23 @@ public void onConfigurationChanged(@NonNull Configuration configuration) {
695693
content.post(() -> content.setLayoutTransition(new LayoutTransition()));
696694
}
697695

696+
private String getLocationString(SharedPreferences weather, Resources resources) {
697+
String location = weather.getString(Weather.LOCATION_NAME,
698+
resources.getString(R.string.location_ip_based));
699+
700+
if (checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED
701+
&& weather.getBoolean(Weather.PRECISE_LOCATION, false)) {
702+
location = resources.getString(R.string.precise_location);
703+
}
704+
705+
return location;
706+
}
707+
708+
@Override
709+
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults, int deviceId) {
710+
super.onRequestPermissionsResult(requestCode, permissions, grantResults, deviceId);
711+
}
712+
698713
private void handleOrientation() {
699714
if (Measurements.isLandscape()) {
700715
titleBar.getLayoutParams().height = Measurements.dpToPx(Measurements.HEADER_SIZE_DP / 3f);

app/src/main/java/com/stario/launcher/activities/settings/dialogs/location/LocationDialog.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,12 @@
3838
import com.stario.launcher.ui.utils.UiUtils;
3939

4040
public class LocationDialog extends ActionDialog {
41+
private OnLocationUpdate listener;
42+
4143
public LocationDialog(@NonNull ThemedActivity activity) {
4244
super(activity);
45+
46+
this.listener = null;
4347
}
4448

4549
@SuppressLint("ClickableViewAccessibility")
@@ -97,6 +101,10 @@ public boolean onTouch(View view, MotionEvent event) {
97101

98102
behavior.setDraggable(true);
99103
behavior.setState(BottomSheetBehavior.STATE_HIDDEN);
104+
105+
if (listener != null) {
106+
listener.onUpdate();
107+
}
100108
});
101109
recycler.setAdapter(adapter);
102110

@@ -127,4 +135,12 @@ protected boolean blurBehind() {
127135
protected int getDesiredInitialState() {
128136
return BottomSheetBehavior.STATE_EXPANDED;
129137
}
138+
139+
public void setOnLocationUpdateListener(OnLocationUpdate listener) {
140+
this.listener = listener;
141+
}
142+
143+
public interface OnLocationUpdate {
144+
void onUpdate();
145+
}
130146
}

0 commit comments

Comments
 (0)