Compare commits
10 commits
Author | SHA1 | Date | |
---|---|---|---|
|
21030cb58c | ||
|
7c81f72439 | ||
|
2d6bc33395 | ||
|
7d529dc42a | ||
|
f7790ef2c7 | ||
|
ed729cb018 | ||
|
1b53652adc | ||
|
da82ba519e | ||
|
2d2425c984 | ||
|
424c213a72 |
16 changed files with 678 additions and 433 deletions
|
@ -9,43 +9,46 @@
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/feedbackButton"
|
android:id="@+id/feedbackButton"
|
||||||
|
style="@style/Widget.AppCompat.Button.Borderless"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:text="@string/feedback"
|
android:text="@string/feedback"
|
||||||
style="@style/Widget.AppCompat.Button.Borderless"
|
android:textColor="?android:textColorSecondary"
|
||||||
tools:drawableTop="@drawable/ic_action_message"/>
|
tools:drawableTop="@drawable/ic_action_message" />
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="1dp"
|
android:layout_width="1dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="?attr/divider_color"/>
|
android:background="?attr/divider_color" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/contactUsButton"
|
android:id="@+id/contactUsButton"
|
||||||
|
style="@style/Widget.AppCompat.Button.Borderless"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:text="@string/contact_us"
|
android:text="@string/contact_us"
|
||||||
style="@style/Widget.AppCompat.Button.Borderless"
|
android:textColor="?android:textColorSecondary"
|
||||||
tools:drawableTop="@drawable/ic_action_message"/>
|
tools:drawableTop="@drawable/ic_action_message" />
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:id="@+id/sendLogButtonDiv"
|
android:id="@+id/sendLogButtonDiv"
|
||||||
android:layout_width="1dp"
|
android:layout_width="1dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="?attr/divider_color"/>
|
android:background="?attr/divider_color" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/sendLogButton"
|
android:id="@+id/sendLogButton"
|
||||||
|
style="@style/Widget.AppCompat.Button.Borderless"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:text="@string/send_log"
|
android:text="@string/send_log"
|
||||||
style="@style/Widget.AppCompat.Button.Borderless"
|
android:textColor="?android:textColorSecondary"
|
||||||
tools:drawableTop="@drawable/ic_crashlog"/>
|
tools:drawableTop="@drawable/ic_crashlog" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
|
@ -84,26 +84,11 @@
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
<net.osmand.plus.widgets.TextViewEx
|
|
||||||
android:id="@+id/inapp_descr"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginLeft="@dimen/list_content_padding_large"
|
|
||||||
android:layout_marginRight="@dimen/list_content_padding_large"
|
|
||||||
android:layout_marginTop="@dimen/title_padding"
|
|
||||||
android:gravity="center"
|
|
||||||
android:text="@string/osm_live_payment_desc"
|
|
||||||
android:textColor="?attr/card_description_text_color"
|
|
||||||
android:textSize="@dimen/default_desc_text_size"
|
|
||||||
osmand:typeface="@string/font_roboto_regular"
|
|
||||||
android:layout_marginStart="@dimen/list_content_padding_large"
|
|
||||||
android:layout_marginEnd="@dimen/list_content_padding_large" />
|
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="@dimen/card_padding"
|
android:layout_marginBottom="@dimen/card_padding"
|
||||||
android:layout_marginTop="@dimen/card_padding">
|
android:layout_marginTop="@dimen/title_padding">
|
||||||
|
|
||||||
<include layout="@layout/purchase_dialog_card_shadow_button"/>
|
<include layout="@layout/purchase_dialog_card_shadow_button"/>
|
||||||
|
|
|
@ -11,6 +11,11 @@
|
||||||
Thx - Hardy
|
Thx - Hardy
|
||||||
|
|
||||||
-->
|
-->
|
||||||
|
<string name="subscription_on_hold_title">OsmAnd Live subscription is on hold</string>
|
||||||
|
<string name="subscription_paused_title">OsmAnd Live subscription has been paused</string>
|
||||||
|
<string name="subscription_expired_title">OsmAnd Live subscription has been expired</string>
|
||||||
|
<string name="subscription_payment_issue_title">There is a problem with your subscription. Click the button to go to the Google Play subscription settings to fix your payment method.</string>
|
||||||
|
<string name="manage_subscription">Manage subscription</string>
|
||||||
<string name="start_finish_icons">Start/finish icons</string>
|
<string name="start_finish_icons">Start/finish icons</string>
|
||||||
<string name="sort_name_ascending">Name: A – Z</string>
|
<string name="sort_name_ascending">Name: A – Z</string>
|
||||||
<string name="sort_name_descending">Name: Z – A</string>
|
<string name="sort_name_descending">Name: Z – A</string>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package net.osmand.plus;
|
package net.osmand.plus;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.app.AlarmManager;
|
import android.app.AlarmManager;
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
|
@ -33,16 +34,14 @@ public class NavigationService extends Service implements LocationListener {
|
||||||
// global id don't conflict with others
|
// global id don't conflict with others
|
||||||
public static int USED_BY_NAVIGATION = 1;
|
public static int USED_BY_NAVIGATION = 1;
|
||||||
public static int USED_BY_GPX = 2;
|
public static int USED_BY_GPX = 2;
|
||||||
public static int USED_BY_LIVE = 4;
|
|
||||||
public final static String USAGE_INTENT = "SERVICE_USED_BY";
|
public final static String USAGE_INTENT = "SERVICE_USED_BY";
|
||||||
public final static String USAGE_OFF_INTERVAL = "SERVICE_OFF_INTERVAL";
|
public final static String USAGE_OFF_INTERVAL = "SERVICE_OFF_INTERVAL";
|
||||||
|
|
||||||
private NavigationServiceBinder binder = new NavigationServiceBinder();
|
private final NavigationServiceBinder binder = new NavigationServiceBinder();
|
||||||
|
|
||||||
|
|
||||||
private int serviceOffInterval;
|
private int serviceOffInterval;
|
||||||
private String serviceOffProvider;
|
private String serviceOffProvider;
|
||||||
private int serviceError;
|
private int serviceErrorTimeout;
|
||||||
private long nextManualWakeup;
|
private long nextManualWakeup;
|
||||||
private OsmandSettings settings;
|
private OsmandSettings settings;
|
||||||
private Handler handler;
|
private Handler handler;
|
||||||
|
@ -61,19 +60,11 @@ public class NavigationService extends Service implements LocationListener {
|
||||||
protected synchronized static PowerManager.WakeLock getLock(Context context) {
|
protected synchronized static PowerManager.WakeLock getLock(Context context) {
|
||||||
if (lockStatic == null) {
|
if (lockStatic == null) {
|
||||||
PowerManager mgr = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
|
PowerManager mgr = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
|
||||||
lockStatic = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "OsmandServiceLock");
|
lockStatic = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "OsmAnd:NavigationServiceLock");
|
||||||
}
|
}
|
||||||
return lockStatic;
|
return lockStatic;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Handler getHandler() {
|
|
||||||
return handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getServiceError() {
|
|
||||||
return serviceError;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getNextManualWakeup() {
|
public long getNextManualWakeup() {
|
||||||
return nextManualWakeup;
|
return nextManualWakeup;
|
||||||
}
|
}
|
||||||
|
@ -90,10 +81,6 @@ public class NavigationService extends Service implements LocationListener {
|
||||||
return usedBy;
|
return usedBy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getServiceOffProvider() {
|
|
||||||
return serviceOffProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isUsed() {
|
public boolean isUsed() {
|
||||||
return usedBy != 0;
|
return usedBy != 0;
|
||||||
}
|
}
|
||||||
|
@ -112,13 +99,9 @@ public class NavigationService extends Service implements LocationListener {
|
||||||
} else {
|
} else {
|
||||||
// Issue #3604
|
// Issue #3604
|
||||||
final OsmandApplication app = (OsmandApplication) getApplication();
|
final OsmandApplication app = (OsmandApplication) getApplication();
|
||||||
if ((usedBy == 2) && (app.navigationServiceGpsInterval(app.getSettings().SAVE_GLOBAL_TRACK_INTERVAL.get()) != 0) && (serviceOffInterval == 0)) {
|
if ((usedBy == USED_BY_GPX) && (app.navigationServiceGpsInterval(app.getSettings().SAVE_GLOBAL_TRACK_INTERVAL.get()) != 0) && (serviceOffInterval == 0)) {
|
||||||
serviceOffInterval = app.getSettings().SAVE_GLOBAL_TRACK_INTERVAL.get();
|
serviceOffInterval = app.getSettings().SAVE_GLOBAL_TRACK_INTERVAL.get();
|
||||||
// From onStartCommand:
|
setupServiceErrorTimeout();
|
||||||
serviceError = serviceOffInterval / 5;
|
|
||||||
serviceError = Math.min(serviceError, 12 * 60 * 1000);
|
|
||||||
serviceError = Math.max(serviceError, 30 * 1000);
|
|
||||||
serviceError = Math.min(serviceError, serviceOffInterval);
|
|
||||||
app.setNavigationService(this);
|
app.setNavigationService(this);
|
||||||
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
|
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
|
||||||
pendingIntent = PendingIntent.getBroadcast(this, 0, new Intent(this, OnNavigationServiceAlarmReceiver.class), PendingIntent.FLAG_UPDATE_CURRENT);
|
pendingIntent = PendingIntent.getBroadcast(this, 0, new Intent(this, OnNavigationServiceAlarmReceiver.class), PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
|
@ -132,7 +115,6 @@ public class NavigationService extends Service implements LocationListener {
|
||||||
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 500, serviceOffInterval, pendingIntent);
|
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 500, serviceOffInterval, pendingIntent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
app.getNotificationHelper().updateTopNotification();
|
app.getNotificationHelper().updateTopNotification();
|
||||||
app.getNotificationHelper().refreshNotifications();
|
app.getNotificationHelper().refreshNotifications();
|
||||||
}
|
}
|
||||||
|
@ -150,14 +132,7 @@ public class NavigationService extends Service implements LocationListener {
|
||||||
}
|
}
|
||||||
// use only gps provider
|
// use only gps provider
|
||||||
serviceOffProvider = LocationManager.GPS_PROVIDER;
|
serviceOffProvider = LocationManager.GPS_PROVIDER;
|
||||||
serviceError = serviceOffInterval / 5;
|
setupServiceErrorTimeout();
|
||||||
// 1. not more than 12 mins
|
|
||||||
serviceError = Math.min(serviceError, 12 * 60 * 1000);
|
|
||||||
// 2. not less than 30 seconds
|
|
||||||
serviceError = Math.max(serviceError, 30 * 1000);
|
|
||||||
// 3. not more than serviceOffInterval
|
|
||||||
serviceError = Math.min(serviceError, serviceOffInterval);
|
|
||||||
|
|
||||||
|
|
||||||
locationProvider = app.getLocationProvider();
|
locationProvider = app.getLocationProvider();
|
||||||
app.setNavigationService(this);
|
app.setNavigationService(this);
|
||||||
|
@ -204,7 +179,6 @@ public class NavigationService extends Service implements LocationListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
|
@ -215,6 +189,15 @@ public class NavigationService extends Service implements LocationListener {
|
||||||
return serviceOffInterval == 0;
|
return serviceOffInterval == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setupServiceErrorTimeout() {
|
||||||
|
serviceErrorTimeout = serviceOffInterval / 5;
|
||||||
|
// 1. not more than 12 mins
|
||||||
|
serviceErrorTimeout = Math.min(serviceErrorTimeout, 12 * 60 * 1000);
|
||||||
|
// 2. not less than 30 seconds
|
||||||
|
serviceErrorTimeout = Math.max(serviceErrorTimeout, 30 * 1000);
|
||||||
|
// 3. not more than serviceOffInterval
|
||||||
|
serviceErrorTimeout = Math.min(serviceErrorTimeout, serviceOffInterval);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
|
@ -254,6 +237,29 @@ public class NavigationService extends Service implements LocationListener {
|
||||||
}, 500);
|
}, 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("MissingPermission")
|
||||||
|
public void onWakeUp() {
|
||||||
|
// request location updates
|
||||||
|
final LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
|
||||||
|
try {
|
||||||
|
locationManager.requestLocationUpdates(serviceOffProvider, 0, 0, this);
|
||||||
|
if (serviceOffInterval > serviceErrorTimeout) {
|
||||||
|
handler.postDelayed(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
WakeLock lock = getLock(NavigationService.this);
|
||||||
|
if (lock.isHeld()) {
|
||||||
|
lock.release();
|
||||||
|
locationManager.removeUpdates(NavigationService.this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, serviceErrorTimeout);
|
||||||
|
}
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLocationChanged(Location l) {
|
public void onLocationChanged(Location l) {
|
||||||
if (l != null && !settings.MAP_ACTIVITY_ENABLED.get()) {
|
if (l != null && !settings.MAP_ACTIVITY_ENABLED.get()) {
|
||||||
|
@ -273,7 +279,6 @@ public class NavigationService extends Service implements LocationListener {
|
||||||
}
|
}
|
||||||
locationProvider.setLocationFromService(location, isContinuous());
|
locationProvider.setLocationFromService(location, isContinuous());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
package net.osmand.plus;
|
package net.osmand.plus;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.app.AlarmManager;
|
import android.app.AlarmManager;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.location.LocationManager;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.PowerManager.WakeLock;
|
import android.os.PowerManager.WakeLock;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
|
|
||||||
public class OnNavigationServiceAlarmReceiver extends BroadcastReceiver {
|
public class OnNavigationServiceAlarmReceiver extends BroadcastReceiver {
|
||||||
|
@SuppressLint("WakelockTimeout")
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
final WakeLock lock = NavigationService.getLock(context);
|
final WakeLock lock = NavigationService.getLock(context);
|
||||||
|
@ -25,29 +26,9 @@ public class OnNavigationServiceAlarmReceiver extends BroadcastReceiver {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
rescheduleAlarm(context, service);
|
rescheduleAlarm(context, service);
|
||||||
|
service.onWakeUp();
|
||||||
// request location updates
|
|
||||||
final LocationManager locationManager = (LocationManager) service.getSystemService(Context.LOCATION_SERVICE);
|
|
||||||
try {
|
|
||||||
locationManager.requestLocationUpdates(service.getServiceOffProvider(), 0, 0, service);
|
|
||||||
if (service.getServiceOffInterval() > service.getServiceError()) {
|
|
||||||
service.getHandler().postDelayed(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
// if lock is not anymore held
|
|
||||||
if (lock.isHeld()) {
|
|
||||||
lock.release();
|
|
||||||
locationManager.removeUpdates(service);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, service.getServiceError());
|
|
||||||
}
|
|
||||||
} catch (RuntimeException e) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void rescheduleAlarm(Context context, NavigationService service) {
|
private void rescheduleAlarm(Context context, NavigationService service) {
|
||||||
|
@ -67,5 +48,4 @@ public class OnNavigationServiceAlarmReceiver extends BroadcastReceiver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -509,26 +509,27 @@ public class SQLiteTileSource implements ITileSource {
|
||||||
if(db == null || coordinatesZoom > 25 ){
|
if(db == null || coordinatesZoom > 25 ){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
SQLiteCursor q ;
|
SQLiteCursor cursor ;
|
||||||
if (inversiveZoom) {
|
if (inversiveZoom) {
|
||||||
int minZoom = (17 - minZ) + 1;
|
int minZoom = (17 - minZ) + 1;
|
||||||
// 17 - z = zoom, x << (25 - zoom) = 25th x tile = 8 + z,
|
// 17 - z = zoom, x << (25 - zoom) = 25th x tile = 8 + z,
|
||||||
q = db.rawQuery("SELECT max(x << (8+z)), min(x << (8+z)), max(y << (8+z)), min(y << (8+z))" +
|
cursor = db.rawQuery("SELECT max(x << (8+z)), min(x << (8+z)), max(y << (8+z)), min(y << (8+z))" +
|
||||||
" from tiles where z < "
|
" from tiles where z < "
|
||||||
+ minZoom, new String[0]);
|
+ minZoom, new String[0]);
|
||||||
} else {
|
} else {
|
||||||
q = db.rawQuery("SELECT max(x << (25-z)), min(x << (25-z)), max(y << (25-z)), min(y << (25-z))"
|
cursor = db.rawQuery("SELECT max(x << (25-z)), min(x << (25-z)), max(y << (25-z)), min(y << (25-z))"
|
||||||
+ " from tiles where z > " + minZ,
|
+ " from tiles where z > " + minZ,
|
||||||
new String[0]);
|
new String[0]);
|
||||||
}
|
}
|
||||||
q.moveToFirst();
|
cursor.moveToFirst();
|
||||||
int right = (int) (q.getInt(0) >> (25 - coordinatesZoom));
|
int right = (int) (cursor.getInt(0) >> (25 - coordinatesZoom));
|
||||||
int left = (int) (q.getInt(1) >> (25 - coordinatesZoom));
|
int left = (int) (cursor.getInt(1) >> (25 - coordinatesZoom));
|
||||||
int top = (int) (q.getInt(3) >> (25 - coordinatesZoom));
|
int top = (int) (cursor.getInt(3) >> (25 - coordinatesZoom));
|
||||||
int bottom = (int) (q.getInt(2) >> (25 - coordinatesZoom));
|
int bottom = (int) (cursor.getInt(2) >> (25 - coordinatesZoom));
|
||||||
|
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
return new QuadRect(left, top, right, bottom);
|
return new QuadRect(left, top, right, bottom);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteImage(int x, int y, int zoom) {
|
public void deleteImage(int x, int y, int zoom) {
|
||||||
|
|
|
@ -84,7 +84,7 @@ import net.osmand.plus.base.BaseOsmAndFragment;
|
||||||
import net.osmand.plus.base.ContextMenuFragment;
|
import net.osmand.plus.base.ContextMenuFragment;
|
||||||
import net.osmand.plus.base.FailSafeFuntions;
|
import net.osmand.plus.base.FailSafeFuntions;
|
||||||
import net.osmand.plus.base.MapViewTrackingUtilities;
|
import net.osmand.plus.base.MapViewTrackingUtilities;
|
||||||
import net.osmand.plus.chooseplan.OsmLiveCancelledDialog;
|
import net.osmand.plus.chooseplan.OsmLiveGoneDialog;
|
||||||
import net.osmand.plus.dashboard.DashboardOnMap;
|
import net.osmand.plus.dashboard.DashboardOnMap;
|
||||||
import net.osmand.plus.dialogs.CrashBottomSheetDialogFragment;
|
import net.osmand.plus.dialogs.CrashBottomSheetDialogFragment;
|
||||||
import net.osmand.plus.dialogs.ImportGpxBottomSheetDialogFragment;
|
import net.osmand.plus.dialogs.ImportGpxBottomSheetDialogFragment;
|
||||||
|
@ -845,8 +845,6 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
|
||||||
getSupportFragmentManager().beginTransaction()
|
getSupportFragmentManager().beginTransaction()
|
||||||
.add(R.id.fragmentContainer, new FirstUsageWelcomeFragment(),
|
.add(R.id.fragmentContainer, new FirstUsageWelcomeFragment(),
|
||||||
FirstUsageWelcomeFragment.TAG).commitAllowingStateLoss();
|
FirstUsageWelcomeFragment.TAG).commitAllowingStateLoss();
|
||||||
} else if (!isFirstScreenShowing() && OsmLiveCancelledDialog.shouldShowDialog(app)) {
|
|
||||||
OsmLiveCancelledDialog.showInstance(getSupportFragmentManager());
|
|
||||||
} else if (SendAnalyticsBottomSheetDialogFragment.shouldShowDialog(app)) {
|
} else if (SendAnalyticsBottomSheetDialogFragment.shouldShowDialog(app)) {
|
||||||
SendAnalyticsBottomSheetDialogFragment.showInstance(app, getSupportFragmentManager(), null);
|
SendAnalyticsBottomSheetDialogFragment.showInstance(app, getSupportFragmentManager(), null);
|
||||||
}
|
}
|
||||||
|
@ -2267,6 +2265,9 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
|
||||||
@Override
|
@Override
|
||||||
public void onInAppPurchaseGetItems() {
|
public void onInAppPurchaseGetItems() {
|
||||||
DiscountHelper.checkAndDisplay(this);
|
DiscountHelper.checkAndDisplay(this);
|
||||||
|
if (!isFirstScreenShowing() && OsmLiveGoneDialog.shouldShowDialog(app)) {
|
||||||
|
OsmLiveGoneDialog.showInstance(app, getSupportFragmentManager());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ShowQuickSearchMode {
|
public enum ShowQuickSearchMode {
|
||||||
|
|
|
@ -488,7 +488,6 @@ public class SavingTrackHelper extends SQLiteOpenHelper {
|
||||||
private void addTrackPoint(WptPt pt, boolean newSegment, long time) {
|
private void addTrackPoint(WptPt pt, boolean newSegment, long time) {
|
||||||
List<TrkSegment> points = currentTrack.getModifiablePointsToDisplay();
|
List<TrkSegment> points = currentTrack.getModifiablePointsToDisplay();
|
||||||
Track track = currentTrack.getModifiableGpxFile().tracks.get(0);
|
Track track = currentTrack.getModifiableGpxFile().tracks.get(0);
|
||||||
assert track.segments.size() == points.size();
|
|
||||||
if (points.size() == 0 || newSegment) {
|
if (points.size() == 0 || newSegment) {
|
||||||
points.add(new TrkSegment());
|
points.add(new TrkSegment());
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,17 +44,15 @@ import net.osmand.IProgress;
|
||||||
import net.osmand.IndexConstants;
|
import net.osmand.IndexConstants;
|
||||||
import net.osmand.Location;
|
import net.osmand.Location;
|
||||||
import net.osmand.PlatformUtil;
|
import net.osmand.PlatformUtil;
|
||||||
|
import net.osmand.StateChangedListener;
|
||||||
import net.osmand.data.DataTileManager;
|
import net.osmand.data.DataTileManager;
|
||||||
import net.osmand.data.LatLon;
|
import net.osmand.data.LatLon;
|
||||||
import net.osmand.data.PointDescription;
|
import net.osmand.data.PointDescription;
|
||||||
import net.osmand.plus.settings.backend.ApplicationMode;
|
|
||||||
import net.osmand.plus.ContextMenuAdapter;
|
import net.osmand.plus.ContextMenuAdapter;
|
||||||
import net.osmand.plus.ContextMenuAdapter.ItemClickListener;
|
import net.osmand.plus.ContextMenuAdapter.ItemClickListener;
|
||||||
import net.osmand.plus.ContextMenuItem;
|
import net.osmand.plus.ContextMenuItem;
|
||||||
import net.osmand.plus.OsmandApplication;
|
import net.osmand.plus.OsmandApplication;
|
||||||
import net.osmand.plus.OsmandPlugin;
|
import net.osmand.plus.OsmandPlugin;
|
||||||
import net.osmand.plus.settings.backend.OsmandSettings.CommonPreference;
|
|
||||||
import net.osmand.plus.settings.backend.OsmandSettings.OsmandPreference;
|
|
||||||
import net.osmand.plus.R;
|
import net.osmand.plus.R;
|
||||||
import net.osmand.plus.UiUtilities;
|
import net.osmand.plus.UiUtilities;
|
||||||
import net.osmand.plus.activities.MapActivity;
|
import net.osmand.plus.activities.MapActivity;
|
||||||
|
@ -66,12 +64,15 @@ import net.osmand.plus.mapcontextmenu.MapContextMenu;
|
||||||
import net.osmand.plus.monitoring.OsmandMonitoringPlugin;
|
import net.osmand.plus.monitoring.OsmandMonitoringPlugin;
|
||||||
import net.osmand.plus.myplaces.FavoritesActivity;
|
import net.osmand.plus.myplaces.FavoritesActivity;
|
||||||
import net.osmand.plus.quickaction.QuickActionType;
|
import net.osmand.plus.quickaction.QuickActionType;
|
||||||
|
import net.osmand.plus.settings.backend.ApplicationMode;
|
||||||
|
import net.osmand.plus.settings.backend.OsmandSettings.CommonPreference;
|
||||||
|
import net.osmand.plus.settings.backend.OsmandSettings.OsmandPreference;
|
||||||
import net.osmand.plus.settings.fragments.BaseSettingsFragment;
|
import net.osmand.plus.settings.fragments.BaseSettingsFragment;
|
||||||
import net.osmand.plus.views.layers.MapInfoLayer;
|
|
||||||
import net.osmand.plus.views.OsmandMapLayer.DrawSettings;
|
import net.osmand.plus.views.OsmandMapLayer.DrawSettings;
|
||||||
import net.osmand.plus.views.OsmandMapTileView;
|
import net.osmand.plus.views.OsmandMapTileView;
|
||||||
import net.osmand.plus.views.mapwidgets.widgetstates.WidgetState;
|
import net.osmand.plus.views.layers.MapInfoLayer;
|
||||||
import net.osmand.plus.views.mapwidgets.widgets.TextInfoWidget;
|
import net.osmand.plus.views.mapwidgets.widgets.TextInfoWidget;
|
||||||
|
import net.osmand.plus.views.mapwidgets.widgetstates.WidgetState;
|
||||||
import net.osmand.util.Algorithms;
|
import net.osmand.util.Algorithms;
|
||||||
import net.osmand.util.GeoPointParserUtil.GeoParsedPoint;
|
import net.osmand.util.GeoPointParserUtil.GeoParsedPoint;
|
||||||
import net.osmand.util.MapUtils;
|
import net.osmand.util.MapUtils;
|
||||||
|
@ -158,7 +159,7 @@ public class AudioVideoNotesPlugin extends OsmandPlugin {
|
||||||
public static final int AV_CAMERA_FOCUS_CONTINUOUS = 5;
|
public static final int AV_CAMERA_FOCUS_CONTINUOUS = 5;
|
||||||
// photo shot:
|
// photo shot:
|
||||||
private static int shotId = 0;
|
private static int shotId = 0;
|
||||||
private SoundPool sp = null;
|
private SoundPool soundPool = null;
|
||||||
public static final int FULL_SCEEN_RESULT_DELAY_MS = 3000;
|
public static final int FULL_SCEEN_RESULT_DELAY_MS = 3000;
|
||||||
|
|
||||||
public final CommonPreference<Integer> AV_CAMERA_PICTURE_SIZE;
|
public final CommonPreference<Integer> AV_CAMERA_PICTURE_SIZE;
|
||||||
|
@ -585,6 +586,17 @@ public class AudioVideoNotesPlugin extends OsmandPlugin {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean init(@NonNull final OsmandApplication app, Activity activity) {
|
public boolean init(@NonNull final OsmandApplication app, Activity activity) {
|
||||||
|
if (AV_PHOTO_PLAY_SOUND.get()) {
|
||||||
|
loadCameraSound();
|
||||||
|
}
|
||||||
|
AV_PHOTO_PLAY_SOUND.addListener(new StateChangedListener<Boolean>() {
|
||||||
|
@Override
|
||||||
|
public void stateChanged(Boolean change) {
|
||||||
|
if (AV_PHOTO_PLAY_SOUND.get() && soundPool == null) {
|
||||||
|
loadCameraSound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
// initializeRemoteControlRegistrationMethods();
|
// initializeRemoteControlRegistrationMethods();
|
||||||
// AudioManager am = (AudioManager) app.getSystemService(Context.AUDIO_SERVICE);
|
// AudioManager am = (AudioManager) app.getSystemService(Context.AUDIO_SERVICE);
|
||||||
// if (am != null) {
|
// if (am != null) {
|
||||||
|
@ -593,6 +605,21 @@ public class AudioVideoNotesPlugin extends OsmandPlugin {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void loadCameraSound() {
|
||||||
|
if (soundPool == null) {
|
||||||
|
soundPool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);
|
||||||
|
}
|
||||||
|
if (shotId == 0) {
|
||||||
|
try {
|
||||||
|
AssetFileDescriptor assetFileDescriptor = app.getAssets().openFd("sounds/camera_click.ogg");
|
||||||
|
shotId = soundPool.load(assetFileDescriptor, 1);
|
||||||
|
assetFileDescriptor.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("cannot get shotId for sounds/camera_click.ogg");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerLayers(MapActivity activity) {
|
public void registerLayers(MapActivity activity) {
|
||||||
this.mapActivity = activity;
|
this.mapActivity = activity;
|
||||||
|
@ -1327,21 +1354,6 @@ public class AudioVideoNotesPlugin extends OsmandPlugin {
|
||||||
@Override
|
@Override
|
||||||
public void surfaceCreated(SurfaceHolder holder) {
|
public void surfaceCreated(SurfaceHolder holder) {
|
||||||
try {
|
try {
|
||||||
// load sound befor shot
|
|
||||||
if (AV_PHOTO_PLAY_SOUND.get()) {
|
|
||||||
if (sp == null)
|
|
||||||
sp = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);
|
|
||||||
if (shotId == 0) {
|
|
||||||
try {
|
|
||||||
AssetFileDescriptor assetFileDescriptor = app.getAssets().openFd("sounds/camera_click.ogg");
|
|
||||||
shotId = sp.load(assetFileDescriptor, 1);
|
|
||||||
assetFileDescriptor.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("cannot get shotId for sounds/camera_click.ogg");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Parameters parameters = cam.getParameters();
|
Parameters parameters = cam.getParameters();
|
||||||
parameters.setPictureSize(selectedCamPicSize.width, selectedCamPicSize.height);
|
parameters.setPictureSize(selectedCamPicSize.width, selectedCamPicSize.height);
|
||||||
log.debug("takePhotoWithCamera() set Picture size: width=" + selectedCamPicSize.width
|
log.debug("takePhotoWithCamera() set Picture size: width=" + selectedCamPicSize.width
|
||||||
|
@ -1723,6 +1735,11 @@ public class AudioVideoNotesPlugin extends OsmandPlugin {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void disable(OsmandApplication app) {
|
public void disable(OsmandApplication app) {
|
||||||
|
if (soundPool != null) {
|
||||||
|
soundPool.release();
|
||||||
|
soundPool = null;
|
||||||
|
shotId = 0;
|
||||||
|
}
|
||||||
// AudioManager am = (AudioManager) app.getSystemService(Context.AUDIO_SERVICE);
|
// AudioManager am = (AudioManager) app.getSystemService(Context.AUDIO_SERVICE);
|
||||||
// if (am != null) {
|
// if (am != null) {
|
||||||
// unregisterMediaListener(am);
|
// unregisterMediaListener(am);
|
||||||
|
@ -2037,8 +2054,8 @@ public class AudioVideoNotesPlugin extends OsmandPlugin {
|
||||||
photoJpegData = data;
|
photoJpegData = data;
|
||||||
|
|
||||||
if (AV_PHOTO_PLAY_SOUND.get()) {
|
if (AV_PHOTO_PLAY_SOUND.get()) {
|
||||||
if (sp != null && shotId != 0) {
|
if (soundPool != null && shotId != 0) {
|
||||||
sp.play(shotId, 0.7f, 0.7f, 0, 0, 1);
|
soundPool.play(shotId, 0.7f, 0.7f, 0, 0, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,242 +0,0 @@
|
||||||
package net.osmand.plus.chooseplan;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.graphics.Color;
|
|
||||||
import android.graphics.drawable.ColorDrawable;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.ContextThemeWrapper;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.view.Window;
|
|
||||||
import android.widget.ProgressBar;
|
|
||||||
|
|
||||||
import androidx.annotation.ColorRes;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.core.content.ContextCompat;
|
|
||||||
import androidx.fragment.app.FragmentActivity;
|
|
||||||
import androidx.fragment.app.FragmentManager;
|
|
||||||
|
|
||||||
import net.osmand.PlatformUtil;
|
|
||||||
import net.osmand.plus.OsmandApplication;
|
|
||||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
|
||||||
import net.osmand.plus.settings.backend.OsmandSettings.OsmandPreference;
|
|
||||||
import net.osmand.plus.R;
|
|
||||||
import net.osmand.plus.activities.MapActivity;
|
|
||||||
import net.osmand.plus.base.BaseOsmAndDialogFragment;
|
|
||||||
import net.osmand.plus.chooseplan.ChoosePlanDialogFragment.OsmAndFeature;
|
|
||||||
import net.osmand.plus.inapp.InAppPurchaseHelper;
|
|
||||||
import net.osmand.plus.inapp.InAppPurchaseHelper.InAppPurchaseListener;
|
|
||||||
import net.osmand.plus.inapp.InAppPurchaseHelper.InAppPurchaseTaskType;
|
|
||||||
import net.osmand.plus.widgets.TextViewEx;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
|
|
||||||
import static net.osmand.plus.inapp.InAppPurchaseHelper.SUBSCRIPTION_HOLDING_TIME_MSEC;
|
|
||||||
|
|
||||||
public class OsmLiveCancelledDialog extends BaseOsmAndDialogFragment implements InAppPurchaseListener {
|
|
||||||
public static final String TAG = OsmLiveCancelledDialog.class.getSimpleName();
|
|
||||||
private static final Log LOG = PlatformUtil.getLog(OsmLiveCancelledDialog.class);
|
|
||||||
|
|
||||||
private OsmandApplication app;
|
|
||||||
private InAppPurchaseHelper purchaseHelper;
|
|
||||||
|
|
||||||
private boolean nightMode;
|
|
||||||
private View osmLiveButton;
|
|
||||||
|
|
||||||
private final OsmAndFeature[] osmLiveFeatures = {
|
|
||||||
OsmAndFeature.DAILY_MAP_UPDATES,
|
|
||||||
OsmAndFeature.UNLIMITED_DOWNLOADS,
|
|
||||||
OsmAndFeature.WIKIPEDIA_OFFLINE,
|
|
||||||
OsmAndFeature.WIKIVOYAGE_OFFLINE,
|
|
||||||
OsmAndFeature.CONTOUR_LINES_HILLSHADE_MAPS,
|
|
||||||
OsmAndFeature.SEA_DEPTH_MAPS,
|
|
||||||
OsmAndFeature.UNLOCK_ALL_FEATURES,
|
|
||||||
};
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
app = getMyApplication();
|
|
||||||
purchaseHelper = app.getInAppPurchaseHelper();
|
|
||||||
nightMode = isNightMode(getMapActivity() != null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
|
||||||
Activity ctx = requireActivity();
|
|
||||||
int themeId = nightMode ? R.style.OsmandDarkTheme_DarkActionbar : R.style.OsmandLightTheme_DarkActionbar_LightStatusBar;
|
|
||||||
Dialog dialog = new Dialog(ctx, themeId);
|
|
||||||
Window window = dialog.getWindow();
|
|
||||||
if (window != null) {
|
|
||||||
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
|
||||||
if (!getSettings().DO_NOT_USE_ANIMATIONS.get()) {
|
|
||||||
window.getAttributes().windowAnimations = R.style.Animations_Alpha;
|
|
||||||
}
|
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
|
||||||
window.setStatusBarColor(ContextCompat.getColor(ctx, getStatusBarColor()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
|
||||||
Context ctx = getContext();
|
|
||||||
if (ctx == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
int themeRes = nightMode ? R.style.OsmandDarkTheme_DarkActionbar : R.style.OsmandLightTheme_DarkActionbar_LightStatusBar;
|
|
||||||
View view = LayoutInflater.from(new ContextThemeWrapper(getContext(), themeRes))
|
|
||||||
.inflate(R.layout.osmlive_cancelled_dialog_fragment, container, false);
|
|
||||||
|
|
||||||
view.findViewById(R.id.button_close).setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
dismiss();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
TextViewEx infoDescr = (TextViewEx) view.findViewById(R.id.info_description);
|
|
||||||
StringBuilder descr = new StringBuilder();
|
|
||||||
descr.append(getString(R.string.purchase_cancelled_dialog_descr));
|
|
||||||
for (OsmAndFeature feature : osmLiveFeatures) {
|
|
||||||
descr.append("\n").append("— ").append(feature.toHumanString(ctx));
|
|
||||||
}
|
|
||||||
infoDescr.setText(descr);
|
|
||||||
|
|
||||||
osmLiveButton = view.findViewById(R.id.card_button);
|
|
||||||
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public MapActivity getMapActivity() {
|
|
||||||
Activity activity = getActivity();
|
|
||||||
if (activity instanceof MapActivity) {
|
|
||||||
return (MapActivity) activity;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
|
|
||||||
MapActivity mapActivity = getMapActivity();
|
|
||||||
if (mapActivity != null) {
|
|
||||||
mapActivity.disableDrawer();
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean requestingInventory = purchaseHelper != null && purchaseHelper.getActiveTask() == InAppPurchaseTaskType.REQUEST_INVENTORY;
|
|
||||||
setupOsmLiveButton(requestingInventory);
|
|
||||||
|
|
||||||
OsmandPreference<Boolean> firstTimeShown = app.getSettings().LIVE_UPDATES_PURCHASE_CANCELLED_FIRST_DLG_SHOWN;
|
|
||||||
OsmandPreference<Boolean> secondTimeShown = app.getSettings().LIVE_UPDATES_PURCHASE_CANCELLED_SECOND_DLG_SHOWN;
|
|
||||||
if (!firstTimeShown.get()) {
|
|
||||||
firstTimeShown.set(true);
|
|
||||||
} else if (!secondTimeShown.get()) {
|
|
||||||
secondTimeShown.set(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPause() {
|
|
||||||
super.onPause();
|
|
||||||
|
|
||||||
MapActivity mapActivity = getMapActivity();
|
|
||||||
if (mapActivity != null) {
|
|
||||||
mapActivity.enableDrawer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ColorRes
|
|
||||||
protected int getStatusBarColor() {
|
|
||||||
return nightMode ? R.color.status_bar_wikivoyage_dark : R.color.status_bar_wikivoyage_light;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(InAppPurchaseTaskType taskType, String error) {
|
|
||||||
if (taskType == InAppPurchaseTaskType.REQUEST_INVENTORY) {
|
|
||||||
setupOsmLiveButton(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onGetItems() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onItemPurchased(String sku, boolean active) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showProgress(InAppPurchaseTaskType taskType) {
|
|
||||||
if (taskType == InAppPurchaseTaskType.REQUEST_INVENTORY) {
|
|
||||||
setupOsmLiveButton(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dismissProgress(InAppPurchaseTaskType taskType) {
|
|
||||||
if (taskType == InAppPurchaseTaskType.REQUEST_INVENTORY) {
|
|
||||||
setupOsmLiveButton(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupOsmLiveButton(boolean progress) {
|
|
||||||
if (osmLiveButton != null) {
|
|
||||||
ProgressBar progressBar = (ProgressBar) osmLiveButton.findViewById(R.id.card_button_progress);
|
|
||||||
TextViewEx buttonTitle = (TextViewEx) osmLiveButton.findViewById(R.id.card_button_title);
|
|
||||||
TextViewEx buttonSubtitle = (TextViewEx) osmLiveButton.findViewById(R.id.card_button_subtitle);
|
|
||||||
buttonTitle.setText(getString(R.string.osm_live_plan_pricing));
|
|
||||||
buttonSubtitle.setVisibility(View.GONE);
|
|
||||||
if (progress) {
|
|
||||||
buttonTitle.setVisibility(View.GONE);
|
|
||||||
progressBar.setVisibility(View.VISIBLE);
|
|
||||||
osmLiveButton.setOnClickListener(null);
|
|
||||||
} else {
|
|
||||||
buttonTitle.setVisibility(View.VISIBLE);
|
|
||||||
progressBar.setVisibility(View.GONE);
|
|
||||||
osmLiveButton.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
dismiss();
|
|
||||||
FragmentActivity activity = getActivity();
|
|
||||||
if (activity != null) {
|
|
||||||
ChoosePlanDialogFragment.showOsmLiveInstance(activity.getSupportFragmentManager());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean shouldShowDialog(OsmandApplication app) {
|
|
||||||
OsmandSettings settings = app.getSettings();
|
|
||||||
long cancelledTime = settings.LIVE_UPDATES_PURCHASE_CANCELLED_TIME.get();
|
|
||||||
boolean firstTimeShown = settings.LIVE_UPDATES_PURCHASE_CANCELLED_FIRST_DLG_SHOWN.get();
|
|
||||||
boolean secondTimeShown = settings.LIVE_UPDATES_PURCHASE_CANCELLED_SECOND_DLG_SHOWN.get();
|
|
||||||
return cancelledTime > 0
|
|
||||||
&& (!firstTimeShown
|
|
||||||
|| (System.currentTimeMillis() - cancelledTime > SUBSCRIPTION_HOLDING_TIME_MSEC
|
|
||||||
&& !secondTimeShown));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void showInstance(@NonNull FragmentManager fm) {
|
|
||||||
try {
|
|
||||||
if (fm.findFragmentByTag(OsmLiveCancelledDialog.TAG) == null) {
|
|
||||||
OsmLiveCancelledDialog fragment = new OsmLiveCancelledDialog();
|
|
||||||
fragment.show(fm, OsmLiveCancelledDialog.TAG);
|
|
||||||
}
|
|
||||||
} catch (RuntimeException e) {
|
|
||||||
LOG.error("showInstance", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
334
OsmAnd/src/net/osmand/plus/chooseplan/OsmLiveGoneDialog.java
Normal file
334
OsmAnd/src/net/osmand/plus/chooseplan/OsmLiveGoneDialog.java
Normal file
|
@ -0,0 +1,334 @@
|
||||||
|
package net.osmand.plus.chooseplan;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.drawable.ColorDrawable;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.ContextThemeWrapper;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.Window;
|
||||||
|
|
||||||
|
import androidx.annotation.ColorRes;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.fragment.app.DialogFragment;
|
||||||
|
import androidx.fragment.app.FragmentActivity;
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
|
||||||
|
import net.osmand.PlatformUtil;
|
||||||
|
import net.osmand.plus.OsmandApplication;
|
||||||
|
import net.osmand.plus.R;
|
||||||
|
import net.osmand.plus.activities.MapActivity;
|
||||||
|
import net.osmand.plus.base.BaseOsmAndDialogFragment;
|
||||||
|
import net.osmand.plus.chooseplan.ChoosePlanDialogFragment.OsmAndFeature;
|
||||||
|
import net.osmand.plus.inapp.InAppPurchaseHelper;
|
||||||
|
import net.osmand.plus.inapp.InAppPurchases.InAppSubscription;
|
||||||
|
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||||
|
import net.osmand.plus.settings.backend.OsmandSettings.OsmandPreference;
|
||||||
|
import net.osmand.plus.widgets.TextViewEx;
|
||||||
|
import net.osmand.util.Algorithms;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
|
||||||
|
public abstract class OsmLiveGoneDialog extends BaseOsmAndDialogFragment {
|
||||||
|
public static final String TAG = OsmLiveGoneDialog.class.getName();
|
||||||
|
private static final Log LOG = PlatformUtil.getLog(OsmLiveGoneDialog.class);
|
||||||
|
|
||||||
|
private static final long TIME_BETWEEN_DIALOGS_MSEC = 1000 * 60 * 60 * 24 * 3; // 3 days
|
||||||
|
|
||||||
|
private OsmandApplication app;
|
||||||
|
private boolean nightMode;
|
||||||
|
private View osmLiveButton;
|
||||||
|
|
||||||
|
private final OsmAndFeature[] osmLiveFeatures = {
|
||||||
|
OsmAndFeature.DAILY_MAP_UPDATES,
|
||||||
|
OsmAndFeature.UNLIMITED_DOWNLOADS,
|
||||||
|
OsmAndFeature.WIKIPEDIA_OFFLINE,
|
||||||
|
OsmAndFeature.WIKIVOYAGE_OFFLINE,
|
||||||
|
OsmAndFeature.CONTOUR_LINES_HILLSHADE_MAPS,
|
||||||
|
OsmAndFeature.SEA_DEPTH_MAPS,
|
||||||
|
OsmAndFeature.UNLOCK_ALL_FEATURES,
|
||||||
|
};
|
||||||
|
|
||||||
|
public static class OsmLiveOnHoldDialog extends OsmLiveGoneDialog {
|
||||||
|
public static final String TAG = OsmLiveOnHoldDialog.class.getSimpleName();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected OsmLiveButtonType getOsmLiveButtonType() {
|
||||||
|
return OsmLiveButtonType.MANAGE_SUBSCRIPTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getTitle() {
|
||||||
|
return getString(R.string.subscription_on_hold_title);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getSubscriptionDescr() {
|
||||||
|
return getString(R.string.subscription_payment_issue_title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class OsmLivePausedDialog extends OsmLiveGoneDialog {
|
||||||
|
public static final String TAG = OsmLivePausedDialog.class.getSimpleName();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected OsmLiveButtonType getOsmLiveButtonType() {
|
||||||
|
return OsmLiveButtonType.MANAGE_SUBSCRIPTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getTitle() {
|
||||||
|
return getString(R.string.subscription_paused_title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class OsmLiveExpiredDialog extends OsmLiveGoneDialog {
|
||||||
|
public static final String TAG = OsmLiveExpiredDialog.class.getSimpleName();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getTitle() {
|
||||||
|
return getString(R.string.subscription_expired_title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected enum OsmLiveButtonType {
|
||||||
|
PURCHASE_SUBSCRIPTION,
|
||||||
|
MANAGE_SUBSCRIPTION
|
||||||
|
}
|
||||||
|
|
||||||
|
protected OsmLiveButtonType getOsmLiveButtonType() {
|
||||||
|
return OsmLiveButtonType.PURCHASE_SUBSCRIPTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
app = getMyApplication();
|
||||||
|
nightMode = isNightMode(getMapActivity() != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
Activity ctx = requireActivity();
|
||||||
|
int themeId = nightMode ? R.style.OsmandDarkTheme_DarkActionbar : R.style.OsmandLightTheme_DarkActionbar_LightStatusBar;
|
||||||
|
Dialog dialog = new Dialog(ctx, themeId);
|
||||||
|
Window window = dialog.getWindow();
|
||||||
|
if (window != null) {
|
||||||
|
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
||||||
|
if (!getSettings().DO_NOT_USE_ANIMATIONS.get()) {
|
||||||
|
window.getAttributes().windowAnimations = R.style.Animations_Alpha;
|
||||||
|
}
|
||||||
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
|
window.setStatusBarColor(ContextCompat.getColor(ctx, getStatusBarColor()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
Context ctx = getContext();
|
||||||
|
if (ctx == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int themeRes = nightMode ? R.style.OsmandDarkTheme_DarkActionbar : R.style.OsmandLightTheme_DarkActionbar_LightStatusBar;
|
||||||
|
View view = LayoutInflater.from(new ContextThemeWrapper(getContext(), themeRes))
|
||||||
|
.inflate(R.layout.osmlive_gone_dialog_fragment, container, false);
|
||||||
|
|
||||||
|
view.findViewById(R.id.button_close).setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
dismiss();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
TextViewEx title = (TextViewEx) view.findViewById(R.id.title);
|
||||||
|
title.setText(getTitle());
|
||||||
|
TextViewEx infoDescr = (TextViewEx) view.findViewById(R.id.info_description);
|
||||||
|
StringBuilder descr = new StringBuilder();
|
||||||
|
String subscriptionDescr = getSubscriptionDescr();
|
||||||
|
if (!Algorithms.isEmpty(subscriptionDescr)) {
|
||||||
|
descr.append(subscriptionDescr).append("\n\n");
|
||||||
|
}
|
||||||
|
descr.append(getString(R.string.purchase_cancelled_dialog_descr));
|
||||||
|
for (OsmAndFeature feature : osmLiveFeatures) {
|
||||||
|
descr.append("\n").append("— ").append(feature.toHumanString(ctx));
|
||||||
|
}
|
||||||
|
infoDescr.setText(descr);
|
||||||
|
|
||||||
|
osmLiveButton = view.findViewById(R.id.card_button);
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract String getTitle();
|
||||||
|
|
||||||
|
protected String getSubscriptionDescr() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public MapActivity getMapActivity() {
|
||||||
|
Activity activity = getActivity();
|
||||||
|
if (activity instanceof MapActivity) {
|
||||||
|
return (MapActivity) activity;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
|
||||||
|
MapActivity mapActivity = getMapActivity();
|
||||||
|
if (mapActivity != null) {
|
||||||
|
mapActivity.disableDrawer();
|
||||||
|
}
|
||||||
|
|
||||||
|
setupOsmLiveButton();
|
||||||
|
|
||||||
|
OsmandPreference<Long> firstTimeShownTime = app.getSettings().LIVE_UPDATES_EXPIRED_FIRST_DLG_SHOWN_TIME;
|
||||||
|
OsmandPreference<Long> secondTimeShownTime = app.getSettings().LIVE_UPDATES_EXPIRED_SECOND_DLG_SHOWN_TIME;
|
||||||
|
if (firstTimeShownTime.get() == 0) {
|
||||||
|
firstTimeShownTime.set(System.currentTimeMillis());
|
||||||
|
} else if (secondTimeShownTime.get() == 0) {
|
||||||
|
secondTimeShownTime.set(System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
|
||||||
|
MapActivity mapActivity = getMapActivity();
|
||||||
|
if (mapActivity != null) {
|
||||||
|
mapActivity.enableDrawer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ColorRes
|
||||||
|
protected int getStatusBarColor() {
|
||||||
|
return nightMode ? R.color.status_bar_wikivoyage_dark : R.color.status_bar_wikivoyage_light;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupOsmLiveButton() {
|
||||||
|
if (osmLiveButton != null) {
|
||||||
|
TextViewEx buttonTitle = (TextViewEx) osmLiveButton.findViewById(R.id.card_button_title);
|
||||||
|
TextViewEx buttonSubtitle = (TextViewEx) osmLiveButton.findViewById(R.id.card_button_subtitle);
|
||||||
|
switch (getOsmLiveButtonType()) {
|
||||||
|
case PURCHASE_SUBSCRIPTION:
|
||||||
|
buttonTitle.setText(getString(R.string.osm_live_plan_pricing));
|
||||||
|
osmLiveButton.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
dismiss();
|
||||||
|
FragmentActivity activity = getActivity();
|
||||||
|
if (activity != null) {
|
||||||
|
ChoosePlanDialogFragment.showOsmLiveInstance(activity.getSupportFragmentManager());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case MANAGE_SUBSCRIPTION:
|
||||||
|
buttonTitle.setText(getString(R.string.manage_subscription));
|
||||||
|
osmLiveButton.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
dismiss();
|
||||||
|
FragmentActivity activity = getActivity();
|
||||||
|
if (activity != null) {
|
||||||
|
InAppSubscription expiredSubscription = getExpiredSubscription((OsmandApplication) activity.getApplication());
|
||||||
|
if (expiredSubscription != null) {
|
||||||
|
manageSubscription(expiredSubscription.getSku());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buttonSubtitle.setVisibility(View.GONE);
|
||||||
|
buttonTitle.setVisibility(View.VISIBLE);
|
||||||
|
osmLiveButton.findViewById(R.id.card_button_progress).setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void manageSubscription(@Nullable String sku) {
|
||||||
|
Context ctx = getContext();
|
||||||
|
if (ctx != null) {
|
||||||
|
String url = "https://play.google.com/store/account/subscriptions?package=" + ctx.getPackageName();
|
||||||
|
if (!Algorithms.isEmpty(sku)) {
|
||||||
|
url += "&sku=" + sku;
|
||||||
|
}
|
||||||
|
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
|
||||||
|
startActivity(intent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static InAppSubscription getExpiredSubscription(@NonNull OsmandApplication app) {
|
||||||
|
if (!app.getSettings().LIVE_UPDATES_PURCHASED.get()) {
|
||||||
|
InAppPurchaseHelper purchaseHelper = app.getInAppPurchaseHelper();
|
||||||
|
return purchaseHelper.getLiveUpdates().getTopExpiredSubscription();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean shouldShowDialog(@NonNull OsmandApplication app) {
|
||||||
|
InAppSubscription expiredSubscription = getExpiredSubscription(app);
|
||||||
|
if (expiredSubscription == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
OsmandSettings settings = app.getSettings();
|
||||||
|
long firstTimeShownTime = settings.LIVE_UPDATES_EXPIRED_FIRST_DLG_SHOWN_TIME.get();
|
||||||
|
long secondTimeShownTime = settings.LIVE_UPDATES_EXPIRED_SECOND_DLG_SHOWN_TIME.get();
|
||||||
|
return firstTimeShownTime == 0
|
||||||
|
|| (System.currentTimeMillis() - firstTimeShownTime > TIME_BETWEEN_DIALOGS_MSEC && secondTimeShownTime == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showInstance(@NonNull OsmandApplication app, @NonNull FragmentManager fm) {
|
||||||
|
try {
|
||||||
|
InAppSubscription expiredSubscription = getExpiredSubscription(app);
|
||||||
|
if (expiredSubscription == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String tag = null;
|
||||||
|
DialogFragment fragment = null;
|
||||||
|
switch (expiredSubscription.getState()) {
|
||||||
|
case ON_HOLD:
|
||||||
|
tag = OsmLiveOnHoldDialog.TAG;
|
||||||
|
if (fm.findFragmentByTag(tag) == null) {
|
||||||
|
fragment = new OsmLiveOnHoldDialog();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PAUSED:
|
||||||
|
tag = OsmLivePausedDialog.TAG;
|
||||||
|
if (fm.findFragmentByTag(tag) == null) {
|
||||||
|
fragment = new OsmLivePausedDialog();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EXPIRED:
|
||||||
|
tag = OsmLiveExpiredDialog.TAG;
|
||||||
|
if (fm.findFragmentByTag(tag) == null) {
|
||||||
|
fragment = new OsmLiveExpiredDialog();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (fragment != null) {
|
||||||
|
fragment.show(fm, tag);
|
||||||
|
}
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
LOG.error("showInstance", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,20 +22,21 @@ import net.osmand.AndroidNetworkUtils.OnRequestsResultListener;
|
||||||
import net.osmand.AndroidNetworkUtils.RequestResponse;
|
import net.osmand.AndroidNetworkUtils.RequestResponse;
|
||||||
import net.osmand.PlatformUtil;
|
import net.osmand.PlatformUtil;
|
||||||
import net.osmand.plus.OsmandApplication;
|
import net.osmand.plus.OsmandApplication;
|
||||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
|
||||||
import net.osmand.plus.settings.backend.OsmandSettings.OsmandPreference;
|
|
||||||
import net.osmand.plus.R;
|
import net.osmand.plus.R;
|
||||||
import net.osmand.plus.Version;
|
import net.osmand.plus.Version;
|
||||||
import net.osmand.plus.inapp.InAppPurchases.InAppPurchase;
|
import net.osmand.plus.inapp.InAppPurchases.InAppPurchase;
|
||||||
import net.osmand.plus.inapp.InAppPurchases.InAppPurchase.PurchaseState;
|
import net.osmand.plus.inapp.InAppPurchases.InAppPurchase.PurchaseState;
|
||||||
import net.osmand.plus.inapp.InAppPurchases.InAppPurchaseLiveUpdatesOldSubscription;
|
import net.osmand.plus.inapp.InAppPurchases.InAppPurchaseLiveUpdatesOldSubscription;
|
||||||
import net.osmand.plus.inapp.InAppPurchases.InAppSubscription;
|
import net.osmand.plus.inapp.InAppPurchases.InAppSubscription;
|
||||||
|
import net.osmand.plus.inapp.InAppPurchases.InAppSubscription.SubscriptionState;
|
||||||
import net.osmand.plus.inapp.InAppPurchases.InAppSubscriptionIntroductoryInfo;
|
import net.osmand.plus.inapp.InAppPurchases.InAppSubscriptionIntroductoryInfo;
|
||||||
import net.osmand.plus.inapp.InAppPurchases.InAppSubscriptionList;
|
import net.osmand.plus.inapp.InAppPurchases.InAppSubscriptionList;
|
||||||
import net.osmand.plus.inapp.util.BillingManager;
|
import net.osmand.plus.inapp.util.BillingManager;
|
||||||
import net.osmand.plus.inapp.util.BillingManager.BillingUpdatesListener;
|
import net.osmand.plus.inapp.util.BillingManager.BillingUpdatesListener;
|
||||||
import net.osmand.plus.liveupdates.CountrySelectionFragment;
|
import net.osmand.plus.liveupdates.CountrySelectionFragment;
|
||||||
import net.osmand.plus.liveupdates.CountrySelectionFragment.CountryItem;
|
import net.osmand.plus.liveupdates.CountrySelectionFragment.CountryItem;
|
||||||
|
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||||
|
import net.osmand.plus.settings.backend.OsmandSettings.CommonPreference;
|
||||||
import net.osmand.util.Algorithms;
|
import net.osmand.util.Algorithms;
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
|
@ -51,6 +52,7 @@ import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class InAppPurchaseHelper {
|
public class InAppPurchaseHelper {
|
||||||
|
@ -59,11 +61,10 @@ public class InAppPurchaseHelper {
|
||||||
private static final String TAG = InAppPurchaseHelper.class.getSimpleName();
|
private static final String TAG = InAppPurchaseHelper.class.getSimpleName();
|
||||||
private boolean mDebugLog = false;
|
private boolean mDebugLog = false;
|
||||||
|
|
||||||
public static final long SUBSCRIPTION_HOLDING_TIME_MSEC = 1000 * 60 * 60 * 24 * 3; // 3 days
|
|
||||||
|
|
||||||
private InAppPurchases purchases;
|
private InAppPurchases purchases;
|
||||||
private long lastValidationCheckTime;
|
private long lastValidationCheckTime;
|
||||||
private boolean inventoryRequested;
|
private boolean inventoryRequested;
|
||||||
|
private Map<String, SubscriptionState> subscriptionStateMap = new HashMap<>();
|
||||||
|
|
||||||
private static final long PURCHASE_VALIDATION_PERIOD_MSEC = 1000 * 60 * 60 * 24; // daily
|
private static final long PURCHASE_VALIDATION_PERIOD_MSEC = 1000 * 60 * 60 * 24; // daily
|
||||||
// (arbitrary) request code for the purchase flow
|
// (arbitrary) request code for the purchase flow
|
||||||
|
@ -286,6 +287,7 @@ public class InAppPurchaseHelper {
|
||||||
for (Purchase p : purchases) {
|
for (Purchase p : purchases) {
|
||||||
skuSubscriptions.add(p.getSku());
|
skuSubscriptions.add(p.getSku());
|
||||||
}
|
}
|
||||||
|
skuSubscriptions.addAll(subscriptionStateMap.keySet());
|
||||||
|
|
||||||
BillingManager billingManager = getBillingManager();
|
BillingManager billingManager = getBillingManager();
|
||||||
// Have we been disposed of in the meantime? If so, quit.
|
// Have we been disposed of in the meantime? If so, quit.
|
||||||
|
@ -451,6 +453,15 @@ public class InAppPurchaseHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (Entry<String, SubscriptionState> entry : subscriptionStateMap.entrySet()) {
|
||||||
|
SubscriptionState state = entry.getValue();
|
||||||
|
if (state == SubscriptionState.PAUSED || state == SubscriptionState.ON_HOLD) {
|
||||||
|
String sku = entry.getKey();
|
||||||
|
if (!result.contains(sku)) {
|
||||||
|
result.add(sku);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -546,35 +557,28 @@ public class InAppPurchaseHelper {
|
||||||
// Do we have the live updates?
|
// Do we have the live updates?
|
||||||
boolean subscribedToLiveUpdates = false;
|
boolean subscribedToLiveUpdates = false;
|
||||||
List<Purchase> liveUpdatesPurchases = new ArrayList<>();
|
List<Purchase> liveUpdatesPurchases = new ArrayList<>();
|
||||||
for (InAppPurchase p : getLiveUpdates().getAllSubscriptions()) {
|
for (InAppSubscription s : getLiveUpdates().getAllSubscriptions()) {
|
||||||
Purchase purchase = getPurchase(p.getSku());
|
Purchase purchase = getPurchase(s.getSku());
|
||||||
if (purchase != null) {
|
if (purchase != null || s.getState().isActive()) {
|
||||||
liveUpdatesPurchases.add(purchase);
|
if (purchase != null) {
|
||||||
|
liveUpdatesPurchases.add(purchase);
|
||||||
|
}
|
||||||
if (!subscribedToLiveUpdates) {
|
if (!subscribedToLiveUpdates) {
|
||||||
subscribedToLiveUpdates = true;
|
subscribedToLiveUpdates = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OsmandPreference<Long> subscriptionCancelledTime = ctx.getSettings().LIVE_UPDATES_PURCHASE_CANCELLED_TIME;
|
|
||||||
if (!subscribedToLiveUpdates && ctx.getSettings().LIVE_UPDATES_PURCHASED.get()) {
|
if (!subscribedToLiveUpdates && ctx.getSettings().LIVE_UPDATES_PURCHASED.get()) {
|
||||||
if (subscriptionCancelledTime.get() == 0) {
|
ctx.getSettings().LIVE_UPDATES_PURCHASED.set(false);
|
||||||
subscriptionCancelledTime.set(System.currentTimeMillis());
|
if (!isDepthContoursPurchased(ctx)) {
|
||||||
ctx.getSettings().LIVE_UPDATES_PURCHASE_CANCELLED_FIRST_DLG_SHOWN.set(false);
|
ctx.getSettings().getCustomRenderBooleanProperty("depthContours").set(false);
|
||||||
ctx.getSettings().LIVE_UPDATES_PURCHASE_CANCELLED_SECOND_DLG_SHOWN.set(false);
|
|
||||||
} else if (System.currentTimeMillis() - subscriptionCancelledTime.get() > SUBSCRIPTION_HOLDING_TIME_MSEC) {
|
|
||||||
ctx.getSettings().LIVE_UPDATES_PURCHASED.set(false);
|
|
||||||
if (!isDepthContoursPurchased(ctx)) {
|
|
||||||
ctx.getSettings().getCustomRenderBooleanProperty("depthContours").set(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (subscribedToLiveUpdates) {
|
} else if (subscribedToLiveUpdates) {
|
||||||
subscriptionCancelledTime.set(0L);
|
|
||||||
ctx.getSettings().LIVE_UPDATES_PURCHASED.set(true);
|
ctx.getSettings().LIVE_UPDATES_PURCHASED.set(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
lastValidationCheckTime = System.currentTimeMillis();
|
lastValidationCheckTime = System.currentTimeMillis();
|
||||||
logDebug("User " + (subscribedToLiveUpdates ? "HAS" : "DOES NOT HAVE")
|
logDebug("User " + (subscribedToLiveUpdates ? "HAS" : "DOES NOT HAVE") + " live updates purchased.");
|
||||||
+ " live updates purchased.");
|
|
||||||
|
|
||||||
OsmandSettings settings = ctx.getSettings();
|
OsmandSettings settings = ctx.getSettings();
|
||||||
settings.INAPPS_READ.set(true);
|
settings.INAPPS_READ.set(true);
|
||||||
|
@ -644,12 +648,24 @@ public class InAppPurchaseHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (inAppPurchase instanceof InAppSubscription) {
|
if (inAppPurchase instanceof InAppSubscription) {
|
||||||
|
InAppSubscription s = (InAppSubscription) inAppPurchase;
|
||||||
|
|
||||||
|
SubscriptionState state = subscriptionStateMap.get(inAppPurchase.getSku());
|
||||||
|
s.setState(state == null ? SubscriptionState.UNDEFINED : state);
|
||||||
|
CommonPreference<String> statePref = ctx.getSettings().registerStringPreference(
|
||||||
|
s.getSku() + "_state", SubscriptionState.UNDEFINED.getStateStr()).makeGlobal();
|
||||||
|
s.setPrevState(SubscriptionState.getByStateStr(statePref.get()));
|
||||||
|
statePref.set(s.getState().getStateStr());
|
||||||
|
if (s.getState().isGone() && s.hasStateChanged()) {
|
||||||
|
ctx.getSettings().LIVE_UPDATES_EXPIRED_FIRST_DLG_SHOWN_TIME.set(0L);
|
||||||
|
ctx.getSettings().LIVE_UPDATES_EXPIRED_SECOND_DLG_SHOWN_TIME.set(0L);
|
||||||
|
}
|
||||||
|
|
||||||
String introductoryPrice = skuDetails.getIntroductoryPrice();
|
String introductoryPrice = skuDetails.getIntroductoryPrice();
|
||||||
String introductoryPricePeriod = skuDetails.getIntroductoryPricePeriod();
|
String introductoryPricePeriod = skuDetails.getIntroductoryPricePeriod();
|
||||||
String introductoryPriceCycles = skuDetails.getIntroductoryPriceCycles();
|
String introductoryPriceCycles = skuDetails.getIntroductoryPriceCycles();
|
||||||
long introductoryPriceAmountMicros = skuDetails.getIntroductoryPriceAmountMicros();
|
long introductoryPriceAmountMicros = skuDetails.getIntroductoryPriceAmountMicros();
|
||||||
if (!Algorithms.isEmpty(introductoryPrice)) {
|
if (!Algorithms.isEmpty(introductoryPrice)) {
|
||||||
InAppSubscription s = (InAppSubscription) inAppPurchase;
|
|
||||||
try {
|
try {
|
||||||
s.setIntroductoryInfo(new InAppSubscriptionIntroductoryInfo(s, introductoryPrice,
|
s.setIntroductoryInfo(new InAppSubscriptionIntroductoryInfo(s, introductoryPrice,
|
||||||
introductoryPriceAmountMicros, introductoryPricePeriod, introductoryPriceCycles));
|
introductoryPriceAmountMicros, introductoryPricePeriod, introductoryPriceCycles));
|
||||||
|
@ -779,21 +795,33 @@ public class InAppPurchaseHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("StaticFieldLeak")
|
@SuppressLint("StaticFieldLeak")
|
||||||
private class RequestInventoryTask extends AsyncTask<Void, Void, String> {
|
private class RequestInventoryTask extends AsyncTask<Void, Void, String[]> {
|
||||||
|
|
||||||
RequestInventoryTask() {
|
RequestInventoryTask() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String doInBackground(Void... params) {
|
protected String[] doInBackground(Void... params) {
|
||||||
try {
|
try {
|
||||||
Map<String, String> parameters = new HashMap<>();
|
Map<String, String> parameters = new HashMap<>();
|
||||||
parameters.put("androidPackage", ctx.getPackageName());
|
parameters.put("androidPackage", ctx.getPackageName());
|
||||||
addUserInfo(parameters);
|
addUserInfo(parameters);
|
||||||
return AndroidNetworkUtils.sendRequest(ctx,
|
String activeSubscriptionsIds = AndroidNetworkUtils.sendRequest(ctx,
|
||||||
"https://osmand.net/api/subscriptions/active",
|
"https://osmand.net/api/subscriptions/active",
|
||||||
parameters, "Requesting active subscriptions...", false, false);
|
parameters, "Requesting active subscriptions...", false, false);
|
||||||
|
|
||||||
|
String subscriptionsState = null;
|
||||||
|
String userId = ctx.getSettings().BILLING_USER_ID.get();
|
||||||
|
String userToken = ctx.getSettings().BILLING_USER_TOKEN.get();
|
||||||
|
if (!Algorithms.isEmpty(userId) && !Algorithms.isEmpty(userToken)) {
|
||||||
|
parameters.put("userId", userId);
|
||||||
|
parameters.put("userToken", userToken);
|
||||||
|
subscriptionsState = AndroidNetworkUtils.sendRequest(ctx,
|
||||||
|
"https://osmand.net/api/subscriptions/get",
|
||||||
|
parameters, "Requesting subscriptions state...", false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new String[] { activeSubscriptionsIds, subscriptionsState };
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logError("sendRequest Error", e);
|
logError("sendRequest Error", e);
|
||||||
}
|
}
|
||||||
|
@ -801,25 +829,47 @@ public class InAppPurchaseHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(String response) {
|
protected void onPostExecute(String[] response) {
|
||||||
logDebug("Response=" + response);
|
logDebug("Response=" + Arrays.toString(response));
|
||||||
if (response != null) {
|
String activeSubscriptionsIdsJson = response[0];
|
||||||
|
String subscriptionsStateJson = response[1];
|
||||||
|
if (activeSubscriptionsIdsJson != null) {
|
||||||
inventoryRequested = true;
|
inventoryRequested = true;
|
||||||
try {
|
try {
|
||||||
JSONObject obj = new JSONObject(response);
|
JSONObject obj = new JSONObject(activeSubscriptionsIdsJson);
|
||||||
JSONArray names = obj.names();
|
JSONArray names = obj.names();
|
||||||
for (int i = 0; i < names.length(); i++) {
|
if (names != null) {
|
||||||
String skuType = names.getString(i);
|
for (int i = 0; i < names.length(); i++) {
|
||||||
JSONObject subObj = obj.getJSONObject(skuType);
|
String skuType = names.getString(i);
|
||||||
String sku = subObj.getString("sku");
|
JSONObject subObj = obj.getJSONObject(skuType);
|
||||||
if (!Algorithms.isEmpty(sku)) {
|
String sku = subObj.getString("sku");
|
||||||
getLiveUpdates().upgradeSubscription(sku);
|
if (!Algorithms.isEmpty(sku)) {
|
||||||
|
getLiveUpdates().upgradeSubscription(sku);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
logError("Json parsing error", e);
|
logError("Json parsing error", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (subscriptionsStateJson != null) {
|
||||||
|
inventoryRequested = true;
|
||||||
|
Map<String, SubscriptionState> subscriptionStateMap = new HashMap<>();
|
||||||
|
try {
|
||||||
|
JSONArray subArrJson = new JSONArray(subscriptionsStateJson);
|
||||||
|
for (int i = 0; i < subArrJson.length(); i++) {
|
||||||
|
JSONObject subObj = subArrJson.getJSONObject(i);
|
||||||
|
String sku = subObj.getString("sku");
|
||||||
|
String state = subObj.getString("state");
|
||||||
|
if (!Algorithms.isEmpty(sku) && !Algorithms.isEmpty(state)) {
|
||||||
|
subscriptionStateMap.put(sku, SubscriptionState.getByStateStr(state));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (JSONException e) {
|
||||||
|
logError("Json parsing error", e);
|
||||||
|
}
|
||||||
|
InAppPurchaseHelper.this.subscriptionStateMap = subscriptionStateMap;
|
||||||
|
}
|
||||||
exec(InAppPurchaseTaskType.REQUEST_INVENTORY, new InAppRunnable() {
|
exec(InAppPurchaseTaskType.REQUEST_INVENTORY, new InAppRunnable() {
|
||||||
@Override
|
@Override
|
||||||
public boolean run(InAppPurchaseHelper helper) {
|
public boolean run(InAppPurchaseHelper helper) {
|
||||||
|
@ -877,9 +927,8 @@ public class InAppPurchaseHelper {
|
||||||
ctx.getSettings().LIVE_UPDATES_PURCHASED.set(true);
|
ctx.getSettings().LIVE_UPDATES_PURCHASED.set(true);
|
||||||
ctx.getSettings().getCustomRenderBooleanProperty("depthContours").set(true);
|
ctx.getSettings().getCustomRenderBooleanProperty("depthContours").set(true);
|
||||||
|
|
||||||
ctx.getSettings().LIVE_UPDATES_PURCHASE_CANCELLED_TIME.set(0L);
|
ctx.getSettings().LIVE_UPDATES_EXPIRED_FIRST_DLG_SHOWN_TIME.set(0L);
|
||||||
ctx.getSettings().LIVE_UPDATES_PURCHASE_CANCELLED_FIRST_DLG_SHOWN.set(false);
|
ctx.getSettings().LIVE_UPDATES_EXPIRED_SECOND_DLG_SHOWN_TIME.set(0L);
|
||||||
ctx.getSettings().LIVE_UPDATES_PURCHASE_CANCELLED_SECOND_DLG_SHOWN.set(false);
|
|
||||||
|
|
||||||
notifyDismissProgress(InAppPurchaseTaskType.PURCHASE_LIVE_UPDATES);
|
notifyDismissProgress(InAppPurchaseTaskType.PURCHASE_LIVE_UPDATES);
|
||||||
notifyItemPurchased(sku, active);
|
notifyItemPurchased(sku, active);
|
||||||
|
|
|
@ -27,6 +27,8 @@ import java.text.NumberFormat;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.Currency;
|
import java.util.Currency;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
@ -258,6 +260,28 @@ public class InAppPurchases {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public InAppSubscription getTopExpiredSubscription() {
|
||||||
|
List<InAppSubscription> expiredSubscriptions = new ArrayList<>();
|
||||||
|
for (InAppSubscription s : getAllSubscriptions()) {
|
||||||
|
if (s.getState().isGone()) {
|
||||||
|
expiredSubscriptions.add(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Collections.sort(expiredSubscriptions, new Comparator<InAppSubscription>() {
|
||||||
|
@Override
|
||||||
|
public int compare(InAppSubscription s1, InAppSubscription s2) {
|
||||||
|
int orderS1 = s1.getState().ordinal();
|
||||||
|
int orderS2 = s2.getState().ordinal();
|
||||||
|
if (orderS1 != orderS2) {
|
||||||
|
return (orderS1 < orderS2) ? -1 : ((orderS1 == orderS2) ? 0 : 1);
|
||||||
|
}
|
||||||
|
return Double.compare(s1.getMonthlyPriceValue(), s2.getMonthlyPriceValue());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return expiredSubscriptions.isEmpty() ? null : expiredSubscriptions.get(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class LiveUpdatesInAppPurchasesFree extends InAppSubscriptionList {
|
public static class LiveUpdatesInAppPurchasesFree extends InAppSubscriptionList {
|
||||||
|
@ -636,9 +660,49 @@ public class InAppPurchases {
|
||||||
private String subscriptionPeriodString;
|
private String subscriptionPeriodString;
|
||||||
private Period subscriptionPeriod;
|
private Period subscriptionPeriod;
|
||||||
private boolean upgrade = false;
|
private boolean upgrade = false;
|
||||||
|
private SubscriptionState state = SubscriptionState.UNDEFINED;
|
||||||
|
private SubscriptionState prevState = SubscriptionState.UNDEFINED;
|
||||||
|
|
||||||
private InAppSubscriptionIntroductoryInfo introductoryInfo;
|
private InAppSubscriptionIntroductoryInfo introductoryInfo;
|
||||||
|
|
||||||
|
public enum SubscriptionState {
|
||||||
|
UNDEFINED("undefined"),
|
||||||
|
ACTIVE("active"),
|
||||||
|
CANCELLED("cancelled"),
|
||||||
|
IN_GRACE_PERIOD("in_grace_period"),
|
||||||
|
ON_HOLD("on_hold"),
|
||||||
|
PAUSED("paused"),
|
||||||
|
EXPIRED("expired");
|
||||||
|
|
||||||
|
private final String stateStr;
|
||||||
|
|
||||||
|
SubscriptionState(@NonNull String stateStr) {
|
||||||
|
this.stateStr = stateStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStateStr() {
|
||||||
|
return stateStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static SubscriptionState getByStateStr(@NonNull String stateStr) {
|
||||||
|
for (SubscriptionState state : SubscriptionState.values()) {
|
||||||
|
if (state.stateStr.equals(stateStr)) {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UNDEFINED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isGone() {
|
||||||
|
return this == ON_HOLD || this == PAUSED || this == EXPIRED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isActive() {
|
||||||
|
return this == ACTIVE || this == CANCELLED || this == IN_GRACE_PERIOD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
InAppSubscription(@NonNull String skuNoVersion, int version) {
|
InAppSubscription(@NonNull String skuNoVersion, int version) {
|
||||||
super(skuNoVersion + "_v" + version);
|
super(skuNoVersion + "_v" + version);
|
||||||
this.skuNoVersion = skuNoVersion;
|
this.skuNoVersion = skuNoVersion;
|
||||||
|
@ -674,6 +738,28 @@ public class InAppPurchases {
|
||||||
return upgrade;
|
return upgrade;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public SubscriptionState getState() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setState(@NonNull SubscriptionState state) {
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public SubscriptionState getPrevState() {
|
||||||
|
return prevState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPrevState(@NonNull SubscriptionState prevState) {
|
||||||
|
this.prevState = prevState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasStateChanged() {
|
||||||
|
return state != prevState;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isAnyPurchased() {
|
public boolean isAnyPurchased() {
|
||||||
if (isPurchased()) {
|
if (isPurchased()) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -1,20 +1,22 @@
|
||||||
package net.osmand.plus.routing;
|
package net.osmand.plus.routing;
|
||||||
|
|
||||||
|
|
||||||
|
import android.content.res.AssetFileDescriptor;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
import android.media.SoundPool;
|
import android.media.SoundPool;
|
||||||
|
|
||||||
import net.osmand.Location;
|
import net.osmand.Location;
|
||||||
|
import net.osmand.StateChangedListener;
|
||||||
import net.osmand.binary.RouteDataObject;
|
import net.osmand.binary.RouteDataObject;
|
||||||
import net.osmand.data.PointDescription;
|
import net.osmand.data.PointDescription;
|
||||||
import net.osmand.plus.settings.backend.ApplicationMode;
|
|
||||||
import net.osmand.plus.settings.backend.OsmAndAppCustomization.OsmAndAppCustomizationListener;
|
|
||||||
import net.osmand.plus.OsmandApplication;
|
import net.osmand.plus.OsmandApplication;
|
||||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
|
||||||
import net.osmand.plus.helpers.WaypointHelper.LocationPointWrapper;
|
import net.osmand.plus.helpers.WaypointHelper.LocationPointWrapper;
|
||||||
import net.osmand.plus.routing.AlarmInfo.AlarmInfoType;
|
import net.osmand.plus.routing.AlarmInfo.AlarmInfoType;
|
||||||
import net.osmand.plus.routing.RouteCalculationResult.NextDirectionInfo;
|
import net.osmand.plus.routing.RouteCalculationResult.NextDirectionInfo;
|
||||||
import net.osmand.plus.routing.data.StreetName;
|
import net.osmand.plus.routing.data.StreetName;
|
||||||
|
import net.osmand.plus.settings.backend.ApplicationMode;
|
||||||
|
import net.osmand.plus.settings.backend.OsmAndAppCustomization.OsmAndAppCustomizationListener;
|
||||||
|
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||||
import net.osmand.plus.voice.AbstractPrologCommandPlayer;
|
import net.osmand.plus.voice.AbstractPrologCommandPlayer;
|
||||||
import net.osmand.plus.voice.CommandBuilder;
|
import net.osmand.plus.voice.CommandBuilder;
|
||||||
import net.osmand.plus.voice.CommandPlayer;
|
import net.osmand.plus.voice.CommandPlayer;
|
||||||
|
@ -80,7 +82,10 @@ public class VoiceRouter {
|
||||||
private int TURN_IN_DISTANCE;
|
private int TURN_IN_DISTANCE;
|
||||||
private int TURN_IN_DISTANCE_END;
|
private int TURN_IN_DISTANCE_END;
|
||||||
private int TURN_NOW_DISTANCE;
|
private int TURN_NOW_DISTANCE;
|
||||||
|
|
||||||
|
private SoundPool soundPool;
|
||||||
|
private int soundClick = -1;
|
||||||
|
|
||||||
private VoiceCommandPending pendingCommand = null;
|
private VoiceCommandPending pendingCommand = null;
|
||||||
private RouteDirectionInfo nextRouteDirection;
|
private RouteDirectionInfo nextRouteDirection;
|
||||||
|
|
||||||
|
@ -103,8 +108,36 @@ public class VoiceRouter {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
app.getAppCustomization().addListener(customizationListener);
|
app.getAppCustomization().addListener(customizationListener);
|
||||||
|
|
||||||
|
if (!isMute()) {
|
||||||
|
loadCameraSound();
|
||||||
|
}
|
||||||
|
settings.VOICE_MUTE.addListener(new StateChangedListener<Boolean>() {
|
||||||
|
@Override
|
||||||
|
public void stateChanged(Boolean change) {
|
||||||
|
if (!isMute() && soundPool == null) {
|
||||||
|
loadCameraSound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void loadCameraSound() {
|
||||||
|
if (soundPool == null) {
|
||||||
|
soundPool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);
|
||||||
|
}
|
||||||
|
if (soundClick == -1) {
|
||||||
|
try {
|
||||||
|
// Taken unaltered from https://freesound.org/people/Corsica_S/sounds/91926/ under license http://creativecommons.org/licenses/by/3.0/ :
|
||||||
|
AssetFileDescriptor assetFileDescriptor = app.getAssets().openFd("sounds/ding.ogg");
|
||||||
|
soundClick = soundPool.load(assetFileDescriptor, 1);
|
||||||
|
assetFileDescriptor.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void setPlayer(CommandPlayer player) {
|
public void setPlayer(CommandPlayer player) {
|
||||||
this.player = player;
|
this.player = player;
|
||||||
if (pendingCommand != null && player != null) {
|
if (pendingCommand != null && player != null) {
|
||||||
|
@ -1015,18 +1048,8 @@ public class VoiceRouter {
|
||||||
if (isMute()) {
|
if (isMute()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SoundPool sp = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);
|
if (soundPool != null && soundClick != -1) {
|
||||||
int soundClick = -1;
|
soundPool.play(soundClick, 1, 1, 0, 0, 1);
|
||||||
boolean success = true;
|
|
||||||
try {
|
|
||||||
// Taken unaltered from https://freesound.org/people/Corsica_S/sounds/91926/ under license http://creativecommons.org/licenses/by/3.0/ :
|
|
||||||
soundClick = sp.load(settings.getContext().getAssets().openFd("sounds/ding.ogg"), 1);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
if (success) {
|
|
||||||
sp.play(soundClick, 1 ,1, 0, 0, 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2003,9 +2003,8 @@ public class OsmandSettings {
|
||||||
public final OsmandPreference<Boolean> BILLING_PURCHASE_TOKEN_SENT = new BooleanPreference("billing_purchase_token_sent", false).makeGlobal();
|
public final OsmandPreference<Boolean> BILLING_PURCHASE_TOKEN_SENT = new BooleanPreference("billing_purchase_token_sent", false).makeGlobal();
|
||||||
public final OsmandPreference<String> BILLING_PURCHASE_TOKENS_SENT = new StringPreference("billing_purchase_tokens_sent", "").makeGlobal();
|
public final OsmandPreference<String> BILLING_PURCHASE_TOKENS_SENT = new StringPreference("billing_purchase_tokens_sent", "").makeGlobal();
|
||||||
public final OsmandPreference<Boolean> LIVE_UPDATES_PURCHASED = new BooleanPreference("billing_live_updates_purchased", false).makeGlobal();
|
public final OsmandPreference<Boolean> LIVE_UPDATES_PURCHASED = new BooleanPreference("billing_live_updates_purchased", false).makeGlobal();
|
||||||
public final OsmandPreference<Long> LIVE_UPDATES_PURCHASE_CANCELLED_TIME = new LongPreference("live_updates_purchase_cancelled_time", 0).makeGlobal();
|
public final OsmandPreference<Long> LIVE_UPDATES_EXPIRED_FIRST_DLG_SHOWN_TIME = new LongPreference("live_updates_expired_first_dlg_shown_time", 0).makeGlobal();
|
||||||
public final OsmandPreference<Boolean> LIVE_UPDATES_PURCHASE_CANCELLED_FIRST_DLG_SHOWN = new BooleanPreference("live_updates_purchase_cancelled_first_dlg_shown", false).makeGlobal();
|
public final OsmandPreference<Long> LIVE_UPDATES_EXPIRED_SECOND_DLG_SHOWN_TIME = new LongPreference("live_updates_expired_second_dlg_shown_time", 0).makeGlobal();
|
||||||
public final OsmandPreference<Boolean> LIVE_UPDATES_PURCHASE_CANCELLED_SECOND_DLG_SHOWN = new BooleanPreference("live_updates_purchase_cancelled_second_dlg_shown", false).makeGlobal();
|
|
||||||
public final OsmandPreference<Boolean> FULL_VERSION_PURCHASED = new BooleanPreference("billing_full_version_purchased", false).makeGlobal();
|
public final OsmandPreference<Boolean> FULL_VERSION_PURCHASED = new BooleanPreference("billing_full_version_purchased", false).makeGlobal();
|
||||||
public final OsmandPreference<Boolean> DEPTH_CONTOURS_PURCHASED = new BooleanPreference("billing_sea_depth_purchased", false).makeGlobal();
|
public final OsmandPreference<Boolean> DEPTH_CONTOURS_PURCHASED = new BooleanPreference("billing_sea_depth_purchased", false).makeGlobal();
|
||||||
public final OsmandPreference<Boolean> EMAIL_SUBSCRIBED = new BooleanPreference("email_subscribed", false).makeGlobal();
|
public final OsmandPreference<Boolean> EMAIL_SUBSCRIBED = new BooleanPreference("email_subscribed", false).makeGlobal();
|
||||||
|
|
|
@ -36,7 +36,7 @@ import static net.osmand.plus.settings.backend.OsmandSettings.TerrainMode.HILLSH
|
||||||
public class TerrainLayer extends MapTileLayer {
|
public class TerrainLayer extends MapTileLayer {
|
||||||
|
|
||||||
private final static Log log = PlatformUtil.getLog(TerrainLayer.class);
|
private final static Log log = PlatformUtil.getLog(TerrainLayer.class);
|
||||||
private Map<String, SQLiteTileSource> resources = new LinkedHashMap<String, SQLiteTileSource>();
|
private Map<String, SQLiteTileSource> resources = new LinkedHashMap<String, SQLiteTileSource>();
|
||||||
private final static String HILLSHADE_CACHE = "hillshade.cache";
|
private final static String HILLSHADE_CACHE = "hillshade.cache";
|
||||||
private final static String SLOPE_CACHE = "slope.cache";
|
private final static String SLOPE_CACHE = "slope.cache";
|
||||||
private int ZOOM_BOUNDARY = 15;
|
private int ZOOM_BOUNDARY = 15;
|
||||||
|
@ -69,7 +69,6 @@ public class TerrainLayer extends MapTileLayer {
|
||||||
} else {
|
} else {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void indexTerrainFiles(final OsmandApplication app) {
|
private void indexTerrainFiles(final OsmandApplication app) {
|
||||||
|
@ -78,7 +77,6 @@ public class TerrainLayer extends MapTileLayer {
|
||||||
private String type = mode.name().toLowerCase();
|
private String type = mode.name().toLowerCase();
|
||||||
@Override
|
@Override
|
||||||
protected Void doInBackground(Void... params) {
|
protected Void doInBackground(Void... params) {
|
||||||
|
|
||||||
File tilesDir = app.getAppPath(IndexConstants.TILES_INDEX_DIR);
|
File tilesDir = app.getAppPath(IndexConstants.TILES_INDEX_DIR);
|
||||||
File cacheDir = app.getCacheDir();
|
File cacheDir = app.getCacheDir();
|
||||||
// fix http://stackoverflow.com/questions/26937152/workaround-for-nexus-9-sqlite-file-write-operations-on-external-dirs
|
// fix http://stackoverflow.com/questions/26937152/workaround-for-nexus-9-sqlite-file-write-operations-on-external-dirs
|
||||||
|
@ -92,17 +90,21 @@ public class TerrainLayer extends MapTileLayer {
|
||||||
sqliteDb = null;
|
sqliteDb = null;
|
||||||
}
|
}
|
||||||
if (sqliteDb != null) {
|
if (sqliteDb != null) {
|
||||||
if (sqliteDb.getVersion() == 0) {
|
try {
|
||||||
sqliteDb.setVersion(1);
|
if (sqliteDb.getVersion() == 0) {
|
||||||
}
|
sqliteDb.setVersion(1);
|
||||||
sqliteDb.execSQL("CREATE TABLE IF NOT EXISTS TILE_SOURCES(filename varchar2(256), date_modified int, left int, right int, top int, bottom int)");
|
}
|
||||||
|
sqliteDb.execSQL("CREATE TABLE IF NOT EXISTS TILE_SOURCES(filename varchar2(256), date_modified int, left int, right int, top int, bottom int)");
|
||||||
|
|
||||||
Map<String, Long> fileModified = new HashMap<String, Long>();
|
Map<String, Long> fileModified = new HashMap<String, Long>();
|
||||||
Map<String, SQLiteTileSource> rs = readFiles(app, tilesDir, fileModified);
|
Map<String, SQLiteTileSource> rs = readFiles(app, tilesDir, fileModified);
|
||||||
indexCachedResources(fileModified, rs);
|
indexCachedResources(fileModified, rs);
|
||||||
indexNonCachedResources(fileModified, rs);
|
indexNonCachedResources(fileModified, rs);
|
||||||
sqliteDb.close();
|
sqliteDb.close();
|
||||||
resources = rs;
|
resources = rs;
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -151,7 +153,6 @@ public class TerrainLayer extends MapTileLayer {
|
||||||
indexedResources.insert(filename, new QuadRect(left, top, right, bottom));
|
indexedResources.insert(filename, new QuadRect(left, top, right, bottom));
|
||||||
fileModified.remove(filename);
|
fileModified.remove(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
} while(cursor.moveToNext());
|
} while(cursor.moveToNext());
|
||||||
}
|
}
|
||||||
cursor.close();
|
cursor.close();
|
||||||
|
@ -173,7 +174,6 @@ public class TerrainLayer extends MapTileLayer {
|
||||||
}
|
}
|
||||||
return rs;
|
return rs;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
executeTaskInBackground(task);
|
executeTaskInBackground(task);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue