[android-auto] Better permissions request

Signed-off-by: Andrew Shkrob <andrew.shkrob.social@yandex.by>
This commit is contained in:
Andrew Shkrob 2023-12-26 01:23:25 +01:00 committed by Roman Tsisyk
parent de3acf645c
commit 59c68f7b41
13 changed files with 447 additions and 65 deletions

View file

@ -443,6 +443,8 @@
android:label="@string/driving_options_title"/>
<activity
android:name="app.organicmaps.MapPlaceholderActivity"/>
<activity
android:name="app.organicmaps.car.screens.permissions.RequestPermissionsActivity"/>
<service
android:name="app.organicmaps.car.CarAppService"
android:exported="true"

View file

@ -27,8 +27,8 @@ import app.organicmaps.routing.NavigationService;
public final class CarAppService extends androidx.car.app.CarAppService
{
private static final String CHANNEL_ID = "ANDROID_AUTO";
private static final int NOTIFICATION_ID = CarAppService.class.getSimpleName().hashCode();
public static final String ANDROID_AUTO_NOTIFICATION_CHANNEL_ID = "ANDROID_AUTO";
public static final String API_CAR_HOST = Const.AUTHORITY + ".car";
public static final String ACTION_SHOW_NAVIGATION_SCREEN = Const.ACTION_PREFIX + ".SHOW_NAVIGATION_SCREEN";
@ -96,11 +96,12 @@ public final class CarAppService extends androidx.car.app.CarAppService
private void createNotificationChannel()
{
final NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
final NotificationChannelCompat notificationChannel = new NotificationChannelCompat.Builder(CHANNEL_ID, NotificationManagerCompat.IMPORTANCE_MIN)
.setName(getString(R.string.car_notification_channel_name))
.setLightsEnabled(false) // less annoying
.setVibrationEnabled(false) // less annoying
.build();
final NotificationChannelCompat notificationChannel =
new NotificationChannelCompat.Builder(ANDROID_AUTO_NOTIFICATION_CHANNEL_ID, NotificationManagerCompat.IMPORTANCE_MIN)
.setName(getString(R.string.car_notification_channel_name))
.setLightsEnabled(false) // less annoying
.setVibrationEnabled(false) // less annoying
.build();
notificationManager.createNotificationChannel(notificationChannel);
}
@ -108,7 +109,7 @@ public final class CarAppService extends androidx.car.app.CarAppService
private Notification getNotification()
{
return NavigationService.getNotificationBuilder(this)
.setChannelId(CHANNEL_ID)
.setChannelId(ANDROID_AUTO_NOTIFICATION_CHANNEL_ID)
.setContentTitle(getString(R.string.aa_connected_to_car_notification_title))
.build();
}

View file

@ -20,15 +20,16 @@ import app.organicmaps.car.screens.ErrorScreen;
import app.organicmaps.car.screens.MapPlaceholderScreen;
import app.organicmaps.car.screens.MapScreen;
import app.organicmaps.car.screens.PlaceScreen;
import app.organicmaps.car.screens.RequestPermissionsScreen;
import app.organicmaps.car.screens.base.BaseMapScreen;
import app.organicmaps.car.screens.download.DownloadMapsScreen;
import app.organicmaps.car.screens.download.DownloadMapsScreenBuilder;
import app.organicmaps.car.screens.download.DownloaderHelpers;
import app.organicmaps.car.screens.permissions.RequestPermissionsScreenBuilder;
import app.organicmaps.car.util.CarSensorsManager;
import app.organicmaps.car.util.CurrentCountryChangedListener;
import app.organicmaps.car.util.IntentUtils;
import app.organicmaps.car.util.ThemeUtils;
import app.organicmaps.car.util.UserActionRequired;
import app.organicmaps.display.DisplayChangedListener;
import app.organicmaps.display.DisplayManager;
import app.organicmaps.display.DisplayType;
@ -184,7 +185,7 @@ public final class CarAppSession extends Session implements DefaultLifecycleObse
screensStack.add(new MapScreen(getCarContext(), mSurfaceRenderer));
if (!LocationUtils.checkFineLocationPermission(getCarContext()))
screensStack.add(new RequestPermissionsScreen(getCarContext(), mSensorsManager::onStart));
screensStack.add(RequestPermissionsScreenBuilder.build(getCarContext(), mSensorsManager::onStart));
if (mDisplayManager.isDeviceDisplayUsed())
{
@ -216,7 +217,7 @@ public final class CarAppSession extends Session implements DefaultLifecycleObse
mSurfaceRenderer.disable();
final MapPlaceholderScreen mapPlaceholderScreen = new MapPlaceholderScreen(getCarContext());
if (!isPermissionsOrErrorScreen(topScreen))
if (topScreen instanceof UserActionRequired)
mScreenManager.popToRoot();
mScreenManager.push(mapPlaceholderScreen);
@ -285,9 +286,4 @@ public final class CarAppSession extends Session implements DefaultLifecycleObse
mScreenManager.push(placeScreen);
}
}
private boolean isPermissionsOrErrorScreen(@NonNull Screen screen)
{
return screen instanceof RequestPermissionsScreen || screen instanceof ErrorScreen;
}
}

View file

@ -12,8 +12,9 @@ import androidx.car.app.model.Template;
import app.organicmaps.R;
import app.organicmaps.car.screens.base.BaseScreen;
import app.organicmaps.car.util.Colors;
import app.organicmaps.car.util.UserActionRequired;
public class ErrorScreen extends BaseScreen
public class ErrorScreen extends BaseScreen implements UserActionRequired
{
@StringRes
private final int mTitle;

View file

@ -0,0 +1,72 @@
package app.organicmaps.car.screens.permissions;
import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationManagerCompat;
import app.organicmaps.R;
import app.organicmaps.base.BaseMwmFragmentActivity;
import app.organicmaps.util.LocationUtils;
import java.util.Objects;
public class RequestPermissionsActivity extends BaseMwmFragmentActivity
{
private static final String[] LOCATION_PERMISSIONS = new String[]{ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION};
@Nullable
private ActivityResultLauncher<String[]> mPermissionsRequest;
@Override
protected void onSafeCreate(@Nullable Bundle savedInstanceState)
{
super.onSafeCreate(savedInstanceState);
setContentView(R.layout.activity_request_permissions);
findViewById(R.id.btn_grant_permissions).setOnClickListener(unused -> openAppPermissionSettings());
mPermissionsRequest = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(),
(grantedPermissions) -> closeIfPermissionsGranted());
mPermissionsRequest.launch(LOCATION_PERMISSIONS);
}
@Override
protected void onResume()
{
super.onResume();
closeIfPermissionsGranted();
}
@Override
protected void onSafeDestroy()
{
super.onSafeDestroy();
Objects.requireNonNull(mPermissionsRequest).unregister();
mPermissionsRequest = null;
}
private void openAppPermissionSettings()
{
final Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.fromParts("package", getPackageName(), null));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
private void closeIfPermissionsGranted()
{
if (!LocationUtils.checkLocationPermission(this))
return;
NotificationManagerCompat.from(this).cancel(RequestPermissionsScreenWithNotification.NOTIFICATION_ID);
finish();
}
}

View file

@ -0,0 +1,29 @@
package app.organicmaps.car.screens.permissions;
import static android.Manifest.permission.POST_NOTIFICATIONS;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import android.os.Build;
import androidx.annotation.NonNull;
import androidx.car.app.CarContext;
import androidx.car.app.Screen;
import androidx.core.content.ContextCompat;
import app.organicmaps.util.log.Logger;
public class RequestPermissionsScreenBuilder
{
private static final String TAG = RequestPermissionsScreenBuilder.class.getSimpleName();
public static Screen build(@NonNull CarContext carContext, @NonNull Runnable permissionsGrantedCallback)
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
ContextCompat.checkSelfPermission(carContext, POST_NOTIFICATIONS) != PERMISSION_GRANTED)
{
Logger.w(TAG, "Permission POST_NOTIFICATIONS is not granted, using API-based permissions request");
return new RequestPermissionsScreenWithApi(carContext, permissionsGrantedCallback);
}
return new RequestPermissionsScreenWithNotification(carContext, permissionsGrantedCallback);
}
}

View file

@ -1,4 +1,4 @@
package app.organicmaps.car.screens;
package app.organicmaps.car.screens.permissions;
import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
@ -15,21 +15,23 @@ import androidx.core.graphics.drawable.IconCompat;
import androidx.lifecycle.LifecycleOwner;
import app.organicmaps.R;
import app.organicmaps.car.screens.ErrorScreen;
import app.organicmaps.car.screens.base.BaseScreen;
import app.organicmaps.car.util.Colors;
import app.organicmaps.car.util.UserActionRequired;
import app.organicmaps.util.LocationUtils;
import java.util.Arrays;
import java.util.List;
public class RequestPermissionsScreen extends BaseScreen
public class RequestPermissionsScreenWithApi extends BaseScreen implements UserActionRequired
{
private static final List<String> LOCATION_PERMISSIONS = Arrays.asList(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION);
@NonNull
private final Runnable mPermissionsGrantedCallback;
public RequestPermissionsScreen(@NonNull CarContext carContext, @NonNull Runnable permissionsGrantedCallback)
public RequestPermissionsScreenWithApi(@NonNull CarContext carContext, @NonNull Runnable permissionsGrantedCallback)
{
super(carContext);
mPermissionsGrantedCallback = permissionsGrantedCallback;
@ -39,7 +41,7 @@ public class RequestPermissionsScreen extends BaseScreen
@Override
public Template onGetTemplate()
{
final MessageTemplate.Builder builder = new MessageTemplate.Builder(getCarContext().getString(R.string.aa_location_permissions_request));
final MessageTemplate.Builder builder = new MessageTemplate.Builder(getCarContext().getString(R.string.aa_request_permission_activity_text));
final Action grantPermissions = new Action.Builder()
.setTitle(getCarContext().getString(R.string.aa_grant_permissions))
.setBackgroundColor(Colors.BUTTON_ACCEPT)
@ -83,4 +85,4 @@ public class RequestPermissionsScreen extends BaseScreen
mPermissionsGrantedCallback.run();
finish();
}
}
}

View file

@ -0,0 +1,124 @@
package app.organicmaps.car.screens.permissions;
import android.Manifest;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Build;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresPermission;
import androidx.car.app.CarContext;
import androidx.car.app.model.Action;
import androidx.car.app.model.CarIcon;
import androidx.car.app.model.Header;
import androidx.car.app.model.MessageTemplate;
import androidx.car.app.model.Template;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.drawable.IconCompat;
import androidx.lifecycle.LifecycleOwner;
import app.organicmaps.R;
import app.organicmaps.car.CarAppService;
import app.organicmaps.car.screens.base.BaseScreen;
import app.organicmaps.car.util.UserActionRequired;
import app.organicmaps.util.LocationUtils;
import app.organicmaps.util.concurrency.ThreadPool;
import app.organicmaps.util.concurrency.UiThread;
import java.util.concurrent.ExecutorService;
public class RequestPermissionsScreenWithNotification extends BaseScreen implements UserActionRequired
{
public static final int NOTIFICATION_ID = RequestPermissionsScreenWithNotification.class.getSimpleName().hashCode();
@NonNull
private final ExecutorService mBackgroundExecutor;
private boolean mIsPermissionCheckEnabled = true;
@NonNull
private final Runnable mPermissionsGrantedCallback;
public RequestPermissionsScreenWithNotification(@NonNull CarContext carContext, @NonNull Runnable permissionsGrantedCallback)
{
super(carContext);
mBackgroundExecutor = ThreadPool.getWorker();
mPermissionsGrantedCallback = permissionsGrantedCallback;
}
@NonNull
@Override
public Template onGetTemplate()
{
final MessageTemplate.Builder builder = new MessageTemplate.Builder(getCarContext().getString(R.string.aa_location_permissions_request));
final Header.Builder headerBuilder = new Header.Builder();
headerBuilder.setStartHeaderAction(Action.APP_ICON);
headerBuilder.setTitle(getCarContext().getString(R.string.aa_grant_permissions));
builder.setHeader(headerBuilder.build());
builder.setIcon(new CarIcon.Builder(IconCompat.createWithResource(getCarContext(), R.drawable.ic_location_off)).build());
return builder.build();
}
@Override
@RequiresPermission(value = Manifest.permission.POST_NOTIFICATIONS)
public void onStart(@NonNull LifecycleOwner owner)
{
mIsPermissionCheckEnabled = true;
mBackgroundExecutor.execute(this::checkPermissions);
sendPermissionsRequestNotification();
}
@Override
public void onStop(@NonNull LifecycleOwner owner)
{
mIsPermissionCheckEnabled = false;
}
@Override
public void onDestroy(@NonNull LifecycleOwner owner)
{
NotificationManagerCompat.from(getCarContext()).cancel(NOTIFICATION_ID);
}
private void checkPermissions()
{
if (!mIsPermissionCheckEnabled)
return;
if (LocationUtils.checkLocationPermission(getCarContext()))
{
UiThread.runLater(() -> {
mPermissionsGrantedCallback.run();
finish();
});
}
else
mBackgroundExecutor.execute(this::checkPermissions);
}
@RequiresPermission(value = Manifest.permission.POST_NOTIFICATIONS)
private void sendPermissionsRequestNotification()
{
final int FLAG_IMMUTABLE = Build.VERSION.SDK_INT < Build.VERSION_CODES.M ? 0 : PendingIntent.FLAG_IMMUTABLE;
final Intent contentIntent = new Intent(getCarContext(), RequestPermissionsActivity.class);
final PendingIntent pendingIntent = PendingIntent.getActivity(getCarContext(), 0, contentIntent,
PendingIntent.FLAG_CANCEL_CURRENT | FLAG_IMMUTABLE);
final NotificationCompat.Builder builder = new NotificationCompat.Builder(getCarContext(), CarAppService.ANDROID_AUTO_NOTIFICATION_CHANNEL_ID);
builder.setCategory(NotificationCompat.CATEGORY_NAVIGATION)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setOngoing(true)
.setShowWhen(false)
.setOnlyAlertOnce(true)
.setSmallIcon(R.drawable.ic_my_location)
.setColor(ContextCompat.getColor(getCarContext(), R.color.notification))
.setContentTitle(getCarContext().getString(R.string.aa_request_permission_notification))
.setContentIntent(pendingIntent);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
builder.setPriority(NotificationManager.IMPORTANCE_HIGH);
NotificationManagerCompat.from(getCarContext()).notify(NOTIFICATION_ID, builder.build());
}
}

View file

@ -0,0 +1,7 @@
package app.organicmaps.car.util;
/// Marker interface for screens that require user action to proceed.
/// These screens can't be dropped from AA's screen stack.
public interface UserActionRequired
{
}

View file

@ -0,0 +1,22 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<size
android:width="120dp"
android:height="120dp" />
<solid android:color="@color/base_accent" />
<corners android:radius="16dp" />
</shape>
</item>
<item>
<vector
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M12,8c-2.21,0 -4,1.79 -4,4 0,2.21 1.79,4 4,4 2.21,0 4,-1.79 4,-4 0,-2.21 -1.79,-4 -4,-4ZM20.94,11c-0.46,-4.17 -3.77,-7.48 -7.94,-7.94v-2.06h-2v2.06c-4.17,0.46 -7.48,3.77 -7.94,7.94h-2.06v2h2.06c0.46,4.17 3.77,7.48 7.94,7.94v2.06h2v-2.06c4.17,-0.46 7.48,-3.77 7.94,-7.94h2.06v-2h-2.06ZM12,19c-3.87,0 -7,-3.13 -7,-7 0,-3.87 3.13,-7 7,-7 3.87,0 7,3.13 7,7 0,3.87 -3.13,7 -7,7Z"
android:fillColor="#FFF"/>
</vector>
</item>
</layer-list>

View file

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?windowBackgroundForced"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="32dp"
android:src="@drawable/ic_location_permission_request" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="32dp"
android:layout_marginStart="32dp"
android:text="@string/aa_request_permission_activity_text"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline4"
android:textStyle="bold" />
<Button
android:id="@+id/btn_grant_permissions"
style="@style/MwmWidget.Button.Accent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="32dp"
android:layout_marginStart="32dp"
android:layout_marginTop="24dp"
android:text="@string/aa_grant_permissions" />
</LinearLayout>

View file

@ -66,7 +66,8 @@
<string name="auto_enum_value" translatable="false">AUTO</string>
<string name="placepage_behavior" translatable="false">com.google.android.material.bottomsheet.BottomSheetBehavior</string>
<string name="car_notification_channel_name" translatable="false">CAR_NOTIFICATION_CHANNEL</string>
<string name="car_notification_channel_name" translatable="false">Car</string>
<string name="android_auto_fgs_explanation_for_special_use" translatable="false">Since Android 14, every Foreground Service must have a type. There is no specific service type for Android Auto.</string>
</resources>

View file

@ -31472,51 +31472,142 @@
[aa_location_permissions_request]
comment = Ask user to grant location permissions
tags = android
en = This application requires access to your location for navigation purposes.
ar = يتطلب هذا التطبيق الوصول إلى موقعك لأغراض التنقل.
az = Bu proqram naviqasiya məqsədləri üçün məkanınıza giriş tələb edir.
be = Гэтаму прылажэнню патрабуецца доступ да вашага месцазнаходжання для навігацыі.
bg = Това приложение изисква достъп до местоположението ви за целите на навигацията.
ca = Aquesta aplicació requereix accés a la vostra ubicació per a navegar.
cs = Tato aplikace vyžaduje přístup k vaší poloze pro účely navigace.
da = Denne applikation kræver adgang til din placering til navigationsformål.
de = Diese Anwendung benötigt für die Navigation Zugriff auf deinen Standort.
el = Η εφαρμογή απαιτεί πρόσβαση στην τοποθεσία σας για τους σκοπούς της πλοήγησης.
es = Esta aplicación necesita acceder a su ubicación para navegar.
et = See rakendus nõuab navigeerimiseks juurdepääsu teie asukohale.
eu = Aplikazio honek zure kokapenerako sarbidea behar du nabigaziorako.
fa = این برنامه برای اهداف ناوبری نیاز به دسترسی به موقعیت مکانی شما دارد.
fi = Tämä sovellus edellyttää sijaintisi tallentamista navigointia varten.
fr = L'application a besoin de l'accès à la localisation pour la navigation.
he = יישום זה דורש גישה למיקום שלך למטרות ניווט.
hi = इस एप्लिकेशन को नेविगेशन उद्देश्यों के लिए आपके स्थान तक पहुंच की आवश्यकता है।
hu = Ez az alkalmazás navigációs célokra hozzáférést igényel az Ön tartózkodási helyéhez.
id = Aplikasi ini memerlukan akses ke lokasi Anda untuk tujuan navigasi.
it = Questa applicazione richiede l'accesso alla tua posizione per la navigazione.
ja = このアプリケーションは、ナビゲーションのために位置情報へのアクセスを必要とする。
ko = 이 애플리케이션을 사용하려면 내비게이션 목적으로 사용자 위치에 액세스해야 합니다.
lv = Lai darbotos navigācija, lietotnei ir nepieciešama ierīces atrašanās vietas informācija.
mr = नेव्हिगेशन हेतूंसाठी या अनुप्रयोगास आपल्या स्थानावर प्रवेश आवश्यक आहे.
nb = Denne applikasjonen krever tilgang til posisjonen din for navigasjonsformål.
nl = Deze applicatie vereist toegang tot je locatie voor navigatiedoeleinden.
pl = Ta aplikacja wymaga dostępu do Twojej lokalizacji do celów nawigacji.
pt = Esta aplicação requer acesso à sua localização para fins de navegação.
pt-BR = Este aplicativo requer acesso à sua localização para fins de navegação.
ro = Această aplicație necesită accesul la locația dvs. în scopul navigării.
ru = Этому приложению необходим доступ к вашему местоположению для навигации.
sk = Táto aplikácia vyžaduje prístup k vašej polohe na účely navigácie.
sr = Ова апликација захтева приступ вашој локацији за потребе навигације.
sv = Denna applikation kräver åtkomst till din plats för navigeringssyften.
sw = Programu hii inahitaji ufikiaji wa eneo lako kwa madhumuni ya urambazaji.
th = แอปพลิเคชันนี้ต้องการการเข้าถึงตำแหน่งของคุณเพื่อจุดประสงค์ในการนำทาง
tr = Bu uygulama, navigasyon amacıyla konumunuza erişim gerektirir.
uk = Ця програма потребує доступу до вашого місцезнаходження для навігаційних цілей.
vi = Ứng dụng này yêu cầu quyền truy cập vào vị trí của bạn cho mục đích điều hướng.
zh-Hans = 本应用程序需要访问您的位置以进行导航。
zh-Hant = 此應用程式需要訪問您的位置以進行導航。
en = Organic Maps needs location access. When it's safe, check the notification on your phone.
af = Organic Maps benodig liggingtoegang. Gaan die kennisgewing op jou foon na wanneer dit veilig is.
ar = تحتاج الخرائط العضوية إلى الوصول إلى الموقع. عندما يكون الوضع آمنًا، تحقق من الإشعارات الموجودة على هاتفك.
be = Organic Maps патрабуе доступу да месцазнаходжання. Калі будзе бяспечна, праверце апавяшчэнне на тэлефоне.
bg = Organic Maps се нуждае от достъп до местоположението. Когато е безопасно, проверете известието на телефона си.
ca = Organic Maps necessita accés a la ubicació. Quan sigui segur, comproveu la notificació al telèfon.
cs = Služba Organic Maps potřebuje přístup k poloze. Když je to bezpečné, zkontrolujte oznámení v telefonu.
da = Organic Maps har brug for placeringsadgang. Når det er sikkert, kan du tjekke notifikationen på din telefon.
de = Organic Maps benötigt Zugriff auf den Standort. Wenn es sicher ist, überprüfe die Benachrichtigung auf deinem Telefon.
el = Η εφαρμογή Organic Maps χρειάζεται πρόσβαση στην τοποθεσία. Όταν είναι ασφαλές, ελέγξτε την ειδοποίηση στο τηλέφωνό σας.
es = Organic Maps necesita acceder a la ubicación. Cuando sea seguro, compruebe la notificación en el teléfono.
es-MX = Organic Maps necesita acceder a la ubicación. Cuando sea seguro, revise la notificación en el teléfono.
et = Organic Maps vajab juurdepääsu asukohale. Kui see on turvaline, kontrollige oma telefonis olevat teadet.
eu = Organic Maps-ek kokapenerako sarbidea behar du. Seguru dagoenean, egiaztatu zure telefonoko jakinarazpena.
fa = Organic Maps به دسترسی به مکان نیاز دارد. وقتی ایمن است، اعلان گوشی خود را بررسی کنید.
fi = Organic Maps tarvitsee sijaintitietoja. Kun se on turvallista, tarkista puhelimesi ilmoitus.
fr = Organic Maps a besoin d'un accès à la localisation. Lorsque c'est sûr, vérifie la notification sur ton téléphone.
he = מפות אורגניות זקוקות לגישה למיקום. כשזה בטוח, בדוק את ההתראה בטלפון שלך.
hi = ऑर्गेनिक मैप्स को स्थान पहुंच की आवश्यकता है। जब यह सुरक्षित हो, तो अपने फ़ोन पर अधिसूचना जांचें।
hu = Az Organic Maps-nek szüksége van a helymeghatározáshoz való hozzáférésre. Ha biztonságos, ellenőrizze az értesítést a telefonján.
id = Organic Maps membutuhkan akses lokasi. Jika sudah aman, periksa notifikasi di ponsel Anda.
it = Organic Maps ha bisogno di accedere alla posizione. Quando è sicuro, controlla la notifica sul tuo telefono.
ja = オーガニック・マップは位置情報へのアクセスを必要とする。安全になったら、携帯電話の通知をチェックしよう。
ko = 오가닉 지도에는 위치 액세스 권한이 필요합니다. 안전해지면 휴대폰에서 알림을 확인합니다.
lt = Organic Maps reikia prieigos prie vietos. Kai bus saugu, patikrinkite pranešimą telefone.
mr = ऑर्गेनिक नकाशेला स्थान प्रवेश आवश्यक आहे. ते सुरक्षित असताना, तुमच्या फोनवरील सूचना तपासा.
nb = Organic Maps trenger posisjonstilgang. Når det er trygt, kan du sjekke varslingen på telefonen.
nl = Organic Maps heeft locatietoegang nodig. Als het veilig is, controleer je de melding op je telefoon.
pl = Aplikacja Organic Maps wymaga dostępu do lokalizacji. Gdy będzie to bezpieczne, sprawdź powiadomienie w telefonie.
pt = O Organic Maps precisa de acesso à localização. Quando for seguro, verifica a notificação no teu telemóvel.
pt-BR = O Organic Maps precisa de acesso à localização. Quando for seguro, verifique a notificação em seu telefone.
ro = Organic Maps are nevoie de acces la locație. Când este sigur, verificați notificarea de pe telefon.
ru = Organic Maps нужен доступ к местоположению. Когда будет безопасно, проверьте уведомление на телефоне.
sk = Služba Organic Maps potrebuje prístup k polohe. Keď je to bezpečné, skontrolujte oznámenie na telefóne.
sv = Organic Maps behöver platsåtkomst. När det är säkert kan du kontrollera aviseringen på din telefon.
sw = Organic Maps zinahitaji ufikiaji wa eneo. Ikiwa salama, angalia arifa kwenye simu yako.
th = แผนที่ทั่วไปจำเป็นต้องเข้าถึงตำแหน่ง เมื่อปลอดภัยแล้ว ให้ตรวจสอบการแจ้งเตือนบนโทรศัพท์ของคุณ
tr = Organic Maps konum erişimine ihtiyacı vardır. Güvenli olduğunda, telefonunuzdaki bildirimi kontrol edin.
uk = Для роботи Organic Maps потрібен доступ до місцезнаходження. Коли це буде безпечно, перевірте сповіщення на телефоні.
vi = Bản đồ không phải trả tiền cần quyền truy cập vị trí. Khi an toàn, hãy kiểm tra thông báo trên điện thoại của bạn.
zh-Hans = 有机地图需要位置访问权限。安全后,查看手机上的通知。
zh-Hant = 有機地圖需要位置存取權限。當安全時,請查看手機上的通知。
[aa_request_permission_notification]
comment = Notification title for permission request from AA.
tags = android
en = This app needs your permission
af = Hierdie toepassing benodig jou toestemming
ar = هذا التطبيق يحتاج إلى إذنك
be = Гэтай праграме патрабуецца ваш дазвол
bg = Това приложение се нуждае от вашето разрешение
ca = Aquesta aplicació necessita el vostre permís
cs = Tato aplikace potřebuje vaše povolení
da = Denne app har brug for din tilladelse
de = Diese App braucht deine Erlaubnis
el = Αυτή η εφαρμογή χρειάζεται την άδειά σας
es = Esta aplicación necesita tu permiso
et = See rakendus vajab teie luba
eu = Aplikazio honek zure baimena behar du
fa = این برنامه به اجازه شما نیاز دارد
fi = Tämä sovellus tarvitsee lupasi
fr = Cette application a besoin de ta permission
he = אפליקציה זו זקוקה לאישור שלך
hi = इस ऐप को आपकी अनुमति की आवश्यकता है
hu = Ennek az alkalmazásnak szüksége van az Ön engedélyére
id = Aplikasi ini membutuhkan izin Anda
it = Questa applicazione ha bisogno del tuo permesso
ja = このアプリはあなたの許可を必要とする
ko = 이 앱은 사용자의 승인이 필요합니다.
lt = Šiai programėlei reikia jūsų leidimo
mr = या अॅपला तुमची परवानगी आवश्यक आहे
nb = Denne appen trenger din tillatelse
nl = Deze app heeft je toestemming nodig
pl = Ta aplikacja wymaga Twojej zgody
pt = Esta aplicação precisa da tua autorização
pt-BR = Este aplicativo precisa da sua permissão
ro = Această aplicație are nevoie de permisiunea dvs.
ru = Этому приложению нужно ваше разрешение
sk = Táto aplikácia potrebuje vaše povolenie
sv = Denna app behöver ditt tillstånd
sw = Programu hii inahitaji idhini yako
th = แอพนี้ต้องได้รับอนุญาตจากคุณ
tr = Bu uygulamanın izninize ihtiyacı var
uk = Ця програма потребує вашого дозволу
vi = Ứng dụng này cần sự cho phép của bạn
zh-Hans = 此应用程序需要您的许可
zh-Hant = 此應用程式需要您的許可
[aa_request_permission_activity_text]
comment = The text in the activity for location permission request.
tags = android
en = Organic Maps in Android Auto needs a location permission to work effectively
af = Organic Maps in Android Auto het 'n liggingtoestemming nodig om effektief te werk
ar = تحتاج الخرائط العضوية في Android Auto إلى إذن تحديد الموقع للعمل بفعالية
be = Для эфектыўнай працы Organic Maps у Android Auto патрабуецца дазвол на вызначэнне месцазнаходжання
bg = Organic Maps в Android Auto се нуждае от разрешение за местоположение, за да работи ефективно
ca = Organic Maps a Android Auto necessita un permís d'ubicació per funcionar de manera eficaç
cs = Organic Maps v systému Android Auto potřebují k efektivní práci povolení k poloze
da = Organic Maps i Android Auto har brug for en lokationstilladelse for at fungere effektivt
de = Organic Maps in Android Auto benötigt eine Standortberechtigung, um effektiv zu funktionieren
el = Η εφαρμογή Organic Maps στο Android Auto χρειάζεται μια άδεια τοποθεσίας για να λειτουργήσει αποτελεσματικά
es = Organic Maps en Android Auto necesita un permiso de localización para funcionar eficazmente
es-MX = Organic Maps en Android Auto necesita un permiso de ubicación para funcionar de manera eficaz
et = Android Auto orgaanilised kaardid vajavad tõhusaks tööks asukoha luba
eu = Android Auto-ko Organic Maps-ek kokapen-baimena behar du eraginkortasunez funtzionatzeko
fa = نقشهu200cهای ارگانیک در Android Auto برای کارکرد مؤثر به مجوز مکان نیاز دارد
fi = Android Auton Organic Maps tarvitsevat sijaintiluvan toimiakseen tehokkaasti.
fr = Organic Maps dans Android Auto a besoin d'une autorisation de localisation pour fonctionner efficacement
he = מפות אורגניות ב-Android Auto זקוקות להרשאת מיקום כדי לעבוד ביעילות
hi = एंड्रॉइड ऑटो में ऑर्गेनिक मैप्स को प्रभावी ढंग से काम करने के लिए स्थान अनुमति की आवश्यकता होती है
hu = Az Android Auto szerves térképeinek a hatékony működéshez helymeghatározási engedélyre van szükségük
id = Organic Maps di Android Auto membutuhkan izin lokasi agar dapat bekerja secara efektif
it = Organic Maps in Android Auto ha bisogno di un permesso di localizzazione per funzionare efficacemente
ja = Android AutoのOrganic Mapsを有効に機能させるには、位置情報の許可が必要である。
ko = 안드로이드 오토의 오가닉 맵이 효과적으로 작동하려면 위치 권한이 필요합니다.
lt = Kad Android Auto sistemoje Organic Maps veiktų efektyviai, reikia leidimo nustatyti buvimo vietą
mr = Android Auto मधील ऑरगॅनिक नकाशे प्रभावीपणे कार्य करण्यासाठी स्थान परवानगी आवश्यक आहे
nb = Organic Maps i Android Auto trenger en posisjonstillatelse for å fungere effektivt
nl = Organic Maps in Android Auto heeft een locatie toestemming nodig om effectief te werken
pl = Organic Maps w Android Auto wymagają uprawnień do lokalizacji, aby działać efektywnie
pt = Os Organic Maps no Android Auto precisam de uma permissão de localização para funcionarem eficazmente
pt-BR = O Organic Maps no Android Auto precisa de uma permissão de localização para funcionar efetivamente
ro = Organic Maps din Android Auto are nevoie de o permisiune de localizare pentru a funcționa eficient
ru = Organic Maps в Android Auto для эффективной работы необходимо разрешение на определение местоположения
sk = Organic Maps v službe Android Auto potrebujú na efektívnu prácu povolenie na určenie polohy
sv = Organic Maps i Android Auto behöver ett platstillstånd för att fungera effektivt
sw = Organic Maps katika Android Auto zinahitaji ruhusa ya eneo ili kufanya kazi kwa ufanisi
th = แผนที่ทั่วไปใน Android Auto ต้องได้รับอนุญาตจากตำแหน่งจึงจะทำงานได้อย่างมีประสิทธิภาพ
tr = Android Auto'daki Organic Maps etkin bir şekilde çalışması için konum izni gerekiyor
uk = Для ефективної роботи Organic Maps в Android Auto потрібен дозвіл на розташування
vi = Bản đồ không phải trả tiền trong Android Auto cần có quyền truy cập vị trí để hoạt động hiệu quả
zh-Hans = Android Auto 中的有机地图需要获得定位许可才能有效工作
zh-Hant = Android Auto 中的有機地圖需要位置權限才能有效運作
[aa_grant_permissions]
comment = Displayed on the Android Auto screen. Grant Permissions button. Must be no more than 18 symbols!
comment = Grant Permissions button.
tags = android
en = Grant Permissions
ar = أذونات المنح