diff --git a/android/app/src/main/java/app/organicmaps/MwmActivity.java b/android/app/src/main/java/app/organicmaps/MwmActivity.java index 974e7dfeb9..794c45449e 100644 --- a/android/app/src/main/java/app/organicmaps/MwmActivity.java +++ b/android/app/src/main/java/app/organicmaps/MwmActivity.java @@ -95,6 +95,7 @@ import app.organicmaps.settings.SettingsActivity; import app.organicmaps.settings.UnitLocale; import app.organicmaps.util.Config; import app.organicmaps.util.LocationUtils; +import app.organicmaps.util.PowerManagment; import app.organicmaps.util.SharingUtils; import app.organicmaps.util.ThemeSwitcher; import app.organicmaps.util.ThemeUtils; @@ -119,6 +120,7 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static app.organicmaps.location.LocationState.FOLLOW; import static app.organicmaps.location.LocationState.FOLLOW_AND_ROTATE; import static app.organicmaps.location.LocationState.LOCATION_TAG; +import static app.organicmaps.util.PowerManagment.POWER_MANAGEMENT_TAG; public class MwmActivity extends BaseMwmFragmentActivity implements PlacePageActivationListener, @@ -157,6 +159,8 @@ public class MwmActivity extends BaseMwmFragmentActivity private static final String MAIN_MENU_ID = "MAIN_MENU_BOTTOM_SHEET"; private static final String LAYERS_MENU_ID = "LAYERS_MENU_BOTTOM_SHEET"; + private static final String POWER_SAVE_DISCLAIMER_SHOWN = "POWER_SAVE_DISCLAIMER_SHOWN"; + @Nullable private MapFragment mMapFragment; @@ -208,8 +212,14 @@ public class MwmActivity extends BaseMwmFragmentActivity @SuppressWarnings("NotNullFieldNotInitialized") @NonNull private ActivityResultLauncher mLocationResolutionRequest; + @SuppressWarnings("NotNullFieldNotInitialized") @NonNull private ActivityResultLauncher mShareLauncher; + @SuppressWarnings("NotNullFieldNotInitialized") + @NonNull + private ActivityResultLauncher mPowerSaveSettings; + @NonNull + private PowerSaveDisclaimerState mPowerSaveDisclaimerState = PowerSaveDisclaimerState.WAS_NOT_SHOWN; @SuppressWarnings("NotNullFieldNotInitialized") @NonNull @@ -227,6 +237,14 @@ public class MwmActivity extends BaseMwmFragmentActivity void onTrackLeftAnimation(float offset); } + public enum PowerSaveDisclaimerState + { + WAS_NOT_SHOWN, + SHOWING_FOR_NAVIGATION, + //SHOWING_FOR_TRACK_RECORDING, + SHOWN, + } + public static Intent createShowMapIntent(@NonNull Context context, @Nullable String countryId) { return new Intent(context, DownloadResourcesLegacyActivity.class) @@ -518,6 +536,8 @@ public class MwmActivity extends BaseMwmFragmentActivity this::onLocationResolutionResult); mPostNotificationPermissionRequest = registerForActivityResult(new ActivityResultContracts.RequestPermission(), this::onPostNotificationPermissionResult); + mPowerSaveSettings = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), + o -> onResumeAfterCheckingPowerSaveSettings()); mShareLauncher = SharingUtils.RegisterLauncher(this); @@ -968,6 +988,8 @@ public class MwmActivity extends BaseMwmFragmentActivity // orientation changing, etc. Otherwise, the saved route might be restored at undesirable moment. RoutingController.get().deleteSavedRoute(); + outState.putBoolean(POWER_SAVE_DISCLAIMER_SHOWN, + mPowerSaveDisclaimerState == PowerSaveDisclaimerState.SHOWN); super.onSaveInstanceState(outState); } @@ -991,6 +1013,9 @@ public class MwmActivity extends BaseMwmFragmentActivity if (!mIsTabletLayout && RoutingController.get().isPlanning()) mRoutingPlanInplaceController.restoreState(savedInstanceState); + + if (savedInstanceState.getBoolean(POWER_SAVE_DISCLAIMER_SHOWN, false)) + mPowerSaveDisclaimerState = PowerSaveDisclaimerState.SHOWN; } @Override @@ -1148,6 +1173,8 @@ public class MwmActivity extends BaseMwmFragmentActivity mLocationResolutionRequest = null; mPostNotificationPermissionRequest.unregister(); mPostNotificationPermissionRequest = null; + mPowerSaveSettings.unregister(); + mPowerSaveSettings = null; if (mRemoveDisplayListener && !isChangingConfigurations()) mDisplayManager.removeListener(DisplayType.Device); } @@ -1929,6 +1956,21 @@ public class MwmActivity extends BaseMwmFragmentActivity Logger.w(TAG, "Permission POST_NOTIFICATIONS has been refused"); } + private void onResumeAfterCheckingPowerSaveSettings() + { + final PowerSaveDisclaimerState state = mPowerSaveDisclaimerState; + // Don't show the disclaimer until end of the current session. + mPowerSaveDisclaimerState = PowerSaveDisclaimerState.SHOWN; + switch (state) + { + case SHOWING_FOR_NAVIGATION -> { + Logger.d(POWER_MANAGEMENT_TAG, "Resuming navigation"); + onRoutingStart(); + } + case SHOWN, WAS_NOT_SHOWN -> Logger.w(POWER_MANAGEMENT_TAG, "Ignoring dangling callback"); + } + } + /** * Called by GoogleFusedLocationProvider to request to GPS and/or Wi-Fi. * @param pendingIntent an intent to launch. @@ -2031,11 +2073,58 @@ public class MwmActivity extends BaseMwmFragmentActivity if (!showRoutingDisclaimer()) return; + // Check for battery saver permission + if (!requestBatterySaverPermission(PowerSaveDisclaimerState.SHOWING_FOR_NAVIGATION)) + return; + closeFloatingPanels(); setFullscreen(false); RoutingController.get().start(); } + public boolean requestBatterySaverPermission(@NonNull PowerSaveDisclaimerState requestedBy) + { + if (!PowerManagment.isSystemPowerSaveMode(this)) + { + Logger.i(POWER_MANAGEMENT_TAG, "Power Save mode is disabled on the device"); + return true; + } + Logger.w(POWER_MANAGEMENT_TAG, "Power Save mode is enabled on the device"); + + if (mPowerSaveDisclaimerState != PowerSaveDisclaimerState.WAS_NOT_SHOWN) + { + Logger.i(POWER_MANAGEMENT_TAG, "The Power Save disclaimer has been already shown in this session"); + return true; + } + + final Intent intent = PowerManagment.makeSystemPowerSaveSettingIntent(this); + if (intent == null) + { + Logger.w(POWER_MANAGEMENT_TAG, "No known way to launch the system Power Save settings"); + return true; + } + + dismissAlertDialog(); + final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this, R.style.MwmTheme_AlertDialog) + .setTitle(R.string.power_save_dialog_title) + .setCancelable(false) + .setMessage(R.string.power_save_dialog_summary) + .setNegativeButton(R.string.not_now, (dialog, which) -> { + Logger.d(POWER_MANAGEMENT_TAG, "The Power Save disclaimer was ignored"); + mPowerSaveDisclaimerState = requestedBy; + onResumeAfterCheckingPowerSaveSettings(); + }) + .setOnDismissListener(dialog -> mAlertDialog = null) + .setPositiveButton(R.string.settings, (dlg, which) -> { + Logger.d(POWER_MANAGEMENT_TAG, "Launching the system Power Save settings"); + mPowerSaveDisclaimerState = requestedBy; + mPowerSaveSettings.launch(intent); + }); + Logger.d(POWER_MANAGEMENT_TAG, "Displaying the Power Save disclaimer"); + mAlertDialog = builder.show(); + return false; + } + @Override public void onBookmarksFileUnsupported(@NonNull Uri uri) { diff --git a/android/app/src/main/java/app/organicmaps/routing/NavigationService.java b/android/app/src/main/java/app/organicmaps/routing/NavigationService.java index 4830f30e46..247853cdd4 100644 --- a/android/app/src/main/java/app/organicmaps/routing/NavigationService.java +++ b/android/app/src/main/java/app/organicmaps/routing/NavigationService.java @@ -4,6 +4,7 @@ import static android.Manifest.permission.ACCESS_COARSE_LOCATION; import static android.Manifest.permission.ACCESS_FINE_LOCATION; import static android.Manifest.permission.POST_NOTIFICATIONS; import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static app.organicmaps.util.Constants.Vendor.XIAOMI; import android.annotation.SuppressLint; import android.app.ForegroundServiceStartNotAllowedException; @@ -125,7 +126,7 @@ public class NavigationService extends Service implements LocationListener // Nice colorized notifications should be supported on API=26 and later. // Nonetheless, even on API=32, Xiaomi uses their own legacy implementation that displays white-on-white instead. return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && - !"xiaomi".equalsIgnoreCase(Build.MANUFACTURER); + !XIAOMI.equalsIgnoreCase(Build.MANUFACTURER); } @NonNull diff --git a/android/app/src/main/java/app/organicmaps/util/Config.java b/android/app/src/main/java/app/organicmaps/util/Config.java index 579a7821e6..75b3a1b503 100644 --- a/android/app/src/main/java/app/organicmaps/util/Config.java +++ b/android/app/src/main/java/app/organicmaps/util/Config.java @@ -6,8 +6,8 @@ import android.os.Build; import androidx.annotation.NonNull; import androidx.preference.PreferenceManager; - import app.organicmaps.BuildConfig; +import app.organicmaps.MwmActivity; import app.organicmaps.MwmApplication; import app.organicmaps.R; diff --git a/android/app/src/main/java/app/organicmaps/util/Constants.java b/android/app/src/main/java/app/organicmaps/util/Constants.java index e26115ab00..a9d4f75e9a 100644 --- a/android/app/src/main/java/app/organicmaps/util/Constants.java +++ b/android/app/src/main/java/app/organicmaps/util/Constants.java @@ -51,5 +51,11 @@ public final class Constants private Package() {} } + public static class Vendor + { + public static final String HUAWEI = "HUAWEI"; + public static final String XIAOMI = "XIAOMI"; + } + private Constants() {} } diff --git a/android/app/src/main/java/app/organicmaps/util/PowerManagment.java b/android/app/src/main/java/app/organicmaps/util/PowerManagment.java index 9144045e38..2a443d8b54 100644 --- a/android/app/src/main/java/app/organicmaps/util/PowerManagment.java +++ b/android/app/src/main/java/app/organicmaps/util/PowerManagment.java @@ -1,14 +1,28 @@ package app.organicmaps.util; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.os.Build; +import android.os.PowerManager; +import android.provider.Settings; + import androidx.annotation.IntDef; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import app.organicmaps.Framework; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import static app.organicmaps.util.Constants.Vendor.HUAWEI; +import static app.organicmaps.util.Constants.Vendor.XIAOMI; + public final class PowerManagment { + public static final String POWER_MANAGEMENT_TAG = PowerManagment.class.getName(); + // It should consider to power_managment::Scheme from // map/power_management/power_management_schemas.hpp public static final int NONE = 0; @@ -33,4 +47,54 @@ public final class PowerManagment { Framework.nativeSetPowerManagerScheme(value); } + + public static boolean isSystemPowerSaveMode(@NonNull Context context) + { + if (XIAOMI.equalsIgnoreCase(Build.MANUFACTURER)) + { + final String XIAOMI_SETTING_NAME = "POWER_SAVE_MODE_OPEN"; + final int XIAOMI_SETTING_VALUE = 1; + return Settings.System.getInt(context.getContentResolver(), XIAOMI_SETTING_NAME, -1) + == XIAOMI_SETTING_VALUE; + } + else if (HUAWEI.equalsIgnoreCase(Build.MANUFACTURER)) + { + final String HUAWEI_SETTING_NAME = "SmartModeStatus"; + final int HUAWEI_SETTING_VALUE = 4; + return Settings.System.getInt(context.getContentResolver(), HUAWEI_SETTING_NAME, -1) + == HUAWEI_SETTING_VALUE; + } + + final PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); + if (pm == null) + return false; + + // Huawei and Xiaomi always returns false here. + return pm.isPowerSaveMode(); + } + + public static @Nullable Intent makeSystemPowerSaveSettingIntent(@NonNull Context context) + { + if (XIAOMI.equalsIgnoreCase(Build.MANUFACTURER)) + { + final Intent intent = new Intent(); + intent.setComponent(new ComponentName("com.miui.securitycenter", + "com.miui.powercenter.PowerMainActivity")); + if (Utils.isIntentSupported(context, intent)) + return intent; + } + else if (HUAWEI.equalsIgnoreCase(Build.MANUFACTURER)) + { + final Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY); + if (Utils.isIntentSupported(context, intent)) + return intent; + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) + { + final Intent intent = new Intent(Settings.ACTION_BATTERY_SAVER_SETTINGS); + if (Utils.isIntentSupported(context, intent)) + return intent; + } + return null; + } } diff --git a/android/app/src/main/java/app/organicmaps/util/Utils.java b/android/app/src/main/java/app/organicmaps/util/Utils.java index d0698d1b2a..81f7f086df 100644 --- a/android/app/src/main/java/app/organicmaps/util/Utils.java +++ b/android/app/src/main/java/app/organicmaps/util/Utils.java @@ -38,9 +38,6 @@ import androidx.core.app.NavUtils; import androidx.core.os.BundleCompat; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; - -import com.google.android.material.snackbar.Snackbar; - import app.organicmaps.BuildConfig; import app.organicmaps.MwmActivity; import app.organicmaps.MwmApplication; @@ -48,6 +45,7 @@ import app.organicmaps.R; import app.organicmaps.util.concurrency.UiThread; import app.organicmaps.util.log.Logger; import app.organicmaps.util.log.LogsManager; +import com.google.android.material.snackbar.Snackbar; import java.io.Closeable; import java.io.IOException; diff --git a/data/strings/strings.txt b/data/strings/strings.txt index 06ac70d661..391e55ad3b 100644 --- a/data/strings/strings.txt +++ b/data/strings/strings.txt @@ -10782,6 +10782,49 @@ zh-Hans = 请重试 zh-Hant = 請再試一次 + [not_now] + tags = android + en = Not Now + af = Nie nou nie + ar = ليس الآن + az = İndi yox + be = Не зараз + bg = Не сега + ca = Ara no + cs = Nyní ne + da = Ikke nu + de = Nicht jetzt + el = Όχι τώρα + es = No ahora + et = Mitte praegu + eu = Orain ez + fa = اکنون خیر + fi = Ei nyt + fr = Pas maintenant + he = לא עכשיו + hu = Most nem + id = Jangan Sekarang + it = Non ora + ja = 後で + ko = 나중에 + lt = Ne dabar + mr = आता नाही + nb = Ikke nå + nl = Niet nu + pl = Nie teraz + pt = Agora não + pt-BR = Agora não + ro = Nu acum + ru = Не сейчас + sk = Nie teraz + sv = Inte nu + th = ไว้คราวหลัง + tr = Şimdi Değil + uk = Не зараз + vi = Lúc khác + zh-Hans = 现在不用 + zh-Hant = 現在不要 + [dialog_routing_download_and_build_cross_route] tags = android,ios en = Would you like to download the map and create a more optimal route spanning more than one map? @@ -30977,3 +31020,95 @@ vi = Chỗ ngồi ngoài trời zh-Hans = 室外座位 zh-Hant = 戶外座位 + + [power_save_dialog_title] + comment = Disclaimer title shown when Power Saving Mode is enabled + tags = android + en = Turn Off Power Saving Mode + af = Skakel kragbesparingsmodus af + ar = إيقاف تشغيل وضع توفير الطاقة + az = Enerjiyə qənaət rejimini söndürün + be = Выключыць рэжым энергазберажэння + bg = Изключване на режима за пестене на енергия + ca = Desactiva el mode d'estalvi d'energia + cs = Vypnout režim úspory energie + da = Sluk for strømsparetilstand + de = Energiesparmodus deaktivieren + el = Απενεργοποίηση λειτουργίας εξοικονόμησης ενέργειας + es = Desactivar el modo de ahorro de energía + et = Lülita välja energiasäästurežiim + eu = Desaktibatu energia aurrezteko modua + fa = خاموش کردن حالت صرفه‌جویی در مصرف انرژی + fi = Poista virransäästötila käytöstä + fr = Désactiver le mode économie d'énergie + he = כבה מצב חיסכון באנרגיה + hi = पावर सेविंग मोड बंद करें + hu = Kapcsolja ki az energiatakarékos módot + id = Matikan Mode Hemat Daya + it = Disattiva la modalità di risparmio energetico + ja = 省電力モードをオフにする + ko = 절전 모드 해제 + lt = Išjunkite energijos taupymo režimą + mr = पॉवर सेव्हिंग मोड बंद करा + nb = Slå av strømsparingsmodus + nl = Schakel energiebesparingsmodus uit + pl = Wyłącz tryb oszczędzania energii + pt = Desativar o modo de economia de energia + pt-BR = Desativar o modo de economia de energia + ro = Dezactivați modul de economisire a energiei + ru = Отключить режим энергосбережения + sk = Vypnúť režim úspory energie + sv = Stäng av energisparläget + sw = Zima Hali ya Kuokoa Nguvu + th = ปิดโหมดประหยัดพลังงาน + tr = Güç Tasarrufu Modunu Kapat + uk = Вимкнути режим енергозбереження + vi = Tắt Chế Độ Tiết Kiệm Pin + zh-Hans = 关闭省电模式 + zh-Hant = 關閉省電模式 + + [power_save_dialog_summary] + comment = Disclaimer summary shown when Power Saving Mode is enabled + tags = android + en = For the most accurate navigation, we recommend disabling power saving mode in phone's battery settings. + af = Vir die mees akkurate navigasie, beveel ons aan dat u kragbesparingsmodus in die foon se batteryinstellings deaktiveer. + ar = للحصول على التنقل الأكثر دقة، نوصي بتعطيل وضع توفير الطاقة في إعدادات بطارية الهاتف. + az = Ən dəqiq naviqasiya üçün telefonun batareya parametrlərində enerjiyə qənaət rejimini söndürməyi tövsiyə edirik. + be = Для найбольш дакладнай навігацыі рэкамендуем адключыць рэжым энергазберажэння ў наладах батарэі тэлефона. + bg = За най-точна навигация препоръчваме да деактивирате режима за пестене на енергия в настройките на батерията на телефона. + ca = Per a una navegació més precisa, recomanem desactivar el mode d'estalvi d'energia a la configuració de la bateria del telèfon. + cs = Pro co nejpřesnější navigaci doporučujeme vypnout úsporný režim v nastavení baterie telefonu. + da = For at få den mest nøjagtige navigation anbefaler vi at deaktivere strømbesparende tilstand i telefonens batteriindstillinger. + de = Für eine möglichst genaue Navigation empfehlen wir, den Energiesparmodus in den Akku-Einstellungen des Telefons zu deaktivieren. + el = Για την πιο ακριβή πλοήγηση, συνιστούμε να απενεργοποιήσετε τη λειτουργία εξοικονόμησης ενέργειας στις ρυθμίσεις μπαταρίας του τηλεφώνου. + es = Para una navegación más precisa, te recomendamos que desactives el modo de ahorro de energía en los ajustes de la batería del teléfono. + et = Kõige täpsema navigeerimise tagamiseks soovitame telefoni aku seadetes energiasäästurežiimi välja lülitada. + eu = Nabigazio zehatzena lortzeko, telefonoaren bateriaren ezarpenetan energia aurrezteko modua desgaitzea gomendatzen dugu. + fa = برای دقیقu200cترین ناوبری، توصیه میu200cکنیم حالت صرفهu200cجویی در مصرف انرژی را در تنظیمات باتری گوشی غیرفعال کنید. + fi = Jotta navigointi olisi mahdollisimman tarkkaa, suosittelemme virransäästötilan poistamista käytöstä puhelimen akkuasetuksista. + fr = Pour une navigation plus précise, nous te recommandons de désactiver le mode d'économie d'énergie dans les paramètres de la batterie du téléphone. + he = לניווט המדויק ביותר, אנו ממליצים להשבית את מצב חיסכון בחשמל בהגדרות הסוללה של הטלפון. + hi = सबसे सटीक नेविगेशन के लिए, हम फ़ोन की बैटरी सेटिंग्स में पावर सेविंग मोड को अक्षम करने की सलाह देते हैं। + hu = A legpontosabb navigáció érdekében javasoljuk az energiatakarékos üzemmód kikapcsolását a telefon akkumulátor-beállításaiban. + id = Untuk navigasi yang paling akurat, kami sarankan untuk menonaktifkan mode hemat daya dalam pengaturan baterai ponsel. + it = Per una navigazione più accurata, ti consigliamo di disabilitare la modalità di risparmio energetico nelle impostazioni della batteria del telefono. + ja = 最も正確なナビゲーションのためには、携帯電話のバッテリー設定で省電力モードを無効にすることをお勧めする。 + ko = 가장 정확한 내비게이션을 위해 휴대폰의 배터리 설정에서 절전 모드를 비활성화하는 것이 좋습니다. + lt = Kad navigacija būtų tiksliausia, rekomenduojame išjungti energijos taupymo režimą telefono akumuliatoriaus nustatymuose. + mr = सर्वात अचूक नेव्हिगेशनसाठी, आम्ही फोनच्या बॅटरी सेटिंग्जमध्ये पॉवर सेव्हिंग मोड अक्षम करण्याची शिफारस करतो. + nb = For å få mest mulig nøyaktig navigering anbefaler vi at du deaktiverer strømsparingsmodus i telefonens batteriinnstillinger. + nl = Voor de meest nauwkeurige navigatie raden we aan om de energiebesparende modus uit te schakelen in de batterij-instellingen van de telefoon. + pl = Aby uzyskać najbardziej dokładną nawigację, zalecamy wyłączenie trybu oszczędzania energii w ustawieniach baterii telefonu. + pt = Para uma navegação mais precisa, recomendamos que desactive o modo de poupança de energia nas definições da bateria do telemóvel. + pt-BR = Para obter uma navegação mais precisa, recomendamos que você desative o modo de economia de energia nas configurações de bateria do telefone. + ro = Pentru o navigare cât mai precisă, vă recomandăm să dezactivați modul de economisire a energiei în setările pentru baterie ale telefonului. + ru = Для наиболее точной навигации мы рекомендуем отключить режим энергосбережения в настройках батареи телефона. + sk = Pre čo najpresnejšiu navigáciu odporúčame vypnúť režim úspory energie v nastaveniach batérie telefónu. + sv = För att få den mest exakta navigeringen rekommenderar vi att du avaktiverar energisparläget i telefonens batteriinställningar. + sw = Kwa urambazaji sahihi zaidi, tunapendekeza kuzima hali ya kuokoa nishati katika mipangilio ya betri ya simu. + th = เพื่อการนำทางที่แม่นยำที่สุด เราขอแนะนำให้ปิดใช้งานโหมดประหยัดพลังงานในการตั้งค่าแบตเตอรี่ของโทรศัพท์ + tr = En doğru navigasyon için, telefonun pil ayarlarında güç tasarrufu modunu devre dışı bırakmanızı öneririz. + uk = Для найбільш точної навігації ми рекомендуємо вимкнути режим енергозбереження в налаштуваннях батареї телефону. + vi = Để điều hướng chính xác nhất, chúng tôi khuyên bạn nên tắt chế độ tiết kiệm năng lượng trong cài đặt pin của điện thoại. + zh-Hans = 为了获得最准确的导航,我们建议在手机电池设置中禁用省电模式。 + zh-Hant = 為了獲得最準確的導航,我們建議在手機電池設定中停用省電模式。