Дозволи на Android M: onRequestPermissionsResult () не викликається


291

Я оновлюю наш додаток, щоб використовувати нову систему дозволів виконання M. Все працює за винятком OnRequestPermissionsResult (). Мені потрібно перевірити дозвіл на натискання кнопки, і якщо це успішно, надіслати текстове повідомлення. Коли я надаю дозвіл на це, діалогове вікно закриється, але воно не спрацьовує надіслати текст, поки я знову не натисну кнопку.

Я налагодив і встановив точки перелому в методі onRequestPermissionsResult (), але він ніколи не впадає в нього.

Цей метод називається спочатку:

    private void askForPermission() {
    String[] permissions = new String[]{Manifest.permission.SEND_SMS};
    ActivityCompat.requestPermissions(getActivity(), permissions, PERMISSIONS_CODE);
}

І тоді мій зворотній дзвінок виглядає приблизно так:

    @Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);

    if (requestCode == PERMISSIONS_CODE) {
        for (int i = 0; i < permissions.length; i++) {
            String permission = permissions[i];
            int grantResult = grantResults[i];

            if (permission.equals(Manifest.permission.SEND_SMS)) {
                if (grantResult == PackageManager.PERMISSION_GRANTED) {
                    onPPSButtonPress();
                } else {
                    requestPermissions(new String[]{Manifest.permission.SEND_SMS}, PERMISSIONS_CODE);
                }
            }
        }
    }
}

Хтось стикався з подібною проблемою? Вдячні за будь-яку допомогу в цьому. Дякую

Відповіді:


576

Я зіткнувся з тим же питанням, і я просто знайшов рішення. Під час використання бібліотеки підтримки ви повинні використовувати правильні методи викликів. Наприклад:

  • Перебуваючи в AppCompatActivity , ви повинні використовувати ActivityCompat.requestPermissions ;
  • Коли ви знаходитесь в android.support.v4.app.Fragment , вам слід використовувати просто requestPermissions (це метод екземпляра android.support.v4.app.Fragment)

Якщо ви викликаєте ActivityCompat.requestPermissions у фрагменті, виклик onRequestPermissionsResult викликається активністю, а не фрагментом.

Сподіваюсь, це допомагає!


13
Це також відбувається з noHistory діяльність: code.google.com/p/android-developer-preview/isissue/…
Ентоні Бобенрієт

11
"Коли ви знаходитесь в android.support.v4.app.Fragment, вам слід використовувати просто requestPermissions" - дякую!
Тигран Саркісян

5
@AnthonyBobenrieth, що таке рішення для неісторичних активів? Ми просто не можемо вимагати від них дозволів?
Дін Дикий

2
Посилання розірвано @AnthonyBobenrieth. Чи є рішення, яке не має історії?
fersarr

3
Під час використання Fragment.requestPermissions()батьківська активність фактично отримує onRequestPermissionsResult(). (Це з бібліотекою підтримки 23.3.0)
Хтось десь

101

Ви можете спробувати це:

requestPermissions(permissions, PERMISSIONS_CODE);

Якщо ви викликаєте цей код з фрагмента, у нього є власний метод requestPermissions. Я вважаю, що проблема полягає в тому, що ви викликаєте статичний метод.

Порада, якщо вам потрібен onRequestPermissionsResult()фрагмент: FragmentCompat.requestPermissions(Fragment fragment, String[] permissions, int requestCode)


Дякую за допомогу. Я помітив, що існує метод requestPermissions, якщо його у фрагменті. Я є у фрагменті, і я спробував зателефонувати просто requestPermissions, на жаль, це не вийшло. Я також спробував те, що ви згадали, і це також не вийшло.
AndyOHart

Це працювало для мене в Android M. Але цікаво, чи це спричинить якісь проблеми на пристроях Pre-M?
Бала Вішну

4
@goodgamerguy переконайтеся, що ви не використовуєте код запиту в onRequestPermissionsResult діяльності. якщо ваша діяльність також використовує зворотний виклик onRequestPermissionsResult, вам слід надати за замовчуванням: super.onRequestPermissionsResult (requestCode, дозволи, grantResults);
Тіммі Сімонс

68

Я сподіваюся, що це працює добре

Для активності:

 ActivityCompat.requestPermissions(this,permissionsList,REQUEST_CODE);

Для фрагмента:

 requestPermissions(permissionsList,REQUEST_CODE);

А як щодо SDK 15 і нижче?
zulkarnain shah

4
Вам не потрібен дозвіл щодо SDK 15, потрібен лише зефір та вище версії ..
Санджай Мангаролія

50

Я також зіткнувся з цією проблемою. Якщо ви хочете, щоб діяльність, яка обробляє дозволи не в історії / вхідні дані, ви будете спокусовані змінити свій AndroidManifest.xmlзапис.

Якщо ви встановите активність, яку ви телефонуєте requestPermissionsабо AppCompatActivity.requestPermissionsз якою

android:noHistory="true"
android:excludeFromRecents="true"

у вашому AndroidManifest.xmlтоді onRequestPermissionsResult()не буде називатися. Це вірно , якщо ваша активність є похідним від Activityабо AppCompatActivity.

Це можна виправити, видаливши обидва прапорця з "AndroidManifest.xml" і finishAndRemoveTask()замість цього закінчивши свою діяльність .


Я б швидше не мав видаляти атрибут noHistory, але це рішення, яке працювало для мене. Дякую!
Ерік Шленц

1
У мене була проблема про зефір, але не про Нуга, дякую, що він працював на мене
Йохан Дахмані

37

Якщо у вас є onRequestPermissionsResultактивність і фрагмент, обов'язково зателефонуйте super.onRequestPermissionsResultв активність. Він не потрібен у фрагменті, але є в активності.


Також зауважте, що якщо ви орієнтуєтесь на API (наприклад, наприклад, 19), ви все одно будете знаходитись у системі старої моделі дозволів, і, таким чином, не отримаєте запит, пов’язаний з функцією дозволу, дзвінки
Bonatti

дивіться мою відповідь, якщо ви продовжили іншу діяльність, яка не викликає супер
TouchBoarder

3
Натрапили на цю. FragmentActivity.onRequestPermissionsResult(..)саме туди, куди onRequestPermissionsResult(..)пересилається заклик до фрагменту .
JanPl

@Bonatti Отже, якщо я спробую попросити дозволу в андроїді 4.4.2, я не отримаю результату? Таким чином, я не можу змінити дозволи, а лише побачити їх?
Алекс Фрагоціс

@AlexanderFragotsis Ви отримаєте результат. Різниця полягає лише в тому, що вас не попросять надати дозвіл, натомість система вам буде автоматично надана.
Душан Живкович

33

Застарілий відповідь див. На веб-сторінці : https://developer.android.com/training/permissions/requesting

Всередині фрагменту потрібно зателефонувати:

FragmentCompat.requestPermissions(permissionsList, RequestCode)

Не:

ActivityCompat.requestPermissions(Activity, permissionsList, RequestCode);

2
Відноситься до android.support.v13.app.FragmentCompat
Уді Оші

1
FragmentCompat застарілий як API 27.1.0.
Big McLargeHuge

моя відповідь застаріла, зверніться до: developer.android.com/training/permissions/requesting
Ben.Slama.Jihed

15

Якщо ви використовуєте requestPermissions у фрагменті, він приймає 2 параметри замість 3.

Ви повинні використовувати requestPermissions(permissions, PERMISSIONS_CODE);


1
Насправді це дає відповідь на питання. Викликаючи requestPermissions (метод екземпляра фрагмента) замість ActivityCompat.requestPermissions, метод результату запускається. Яке тут головне питання. Дякуємо Дон
Ваок

15

Якщо з якоїсь причини ви розширили користувацьку активність, розташовану в якійсь зовнішній бібліотеці, яка не викликає супер, вам потрібно буде вручну викликати фрагмент super.onRequestPermissionsResult у своїй активності onRequestPermissionsResult.

YourActivity extends SomeActivityNotCallingSuperOnRequestPermissionsResult{
Fragment requestingFragment;//the fragment requesting the permission
...
@Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if(requestingFragment!=null)
            requestingFragment.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
...

12

У вас є checkPermissions функціонувати до зефіру пристроїв в FragmentCompat . Я використовую так:

FragmentCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                    MY_PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);

2
Це працює лише в тому випадку, якщо дозволено запитати всередині android.app.fragment, і вам доведеться імпортувати бібліотеку support-v13!
MohammadReza

4
FragmentCompat.requestPermissions () не працює з android.support.v4.app.Fragment. Будь-хто знає, як з цим впоратися.
Jutikorn

12

Я з’ясував, що важливо, куди ви дзвоните android.support.v4.app.Fragment.requestPermissions.

Якщо ви зробите це в onCreate(), onRequestPermissionsResult()ніколи не називається.

Рішення: зателефонуйте до нього onActivityCreated();

@Override
public void onActivityCreated(Bundle savedInstanceState) {

    super.onActivityCreated(savedInstanceState);

    if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_DENIED) 
        requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, 0);

}

1
Я зіткнувся з тією ж проблемою, але я не в змозі отримати onActivityCreated()свій код. SDK 23.
kAmol

дивіться developer.android.com/reference/android/app/… або дивіться зразок на сайті mysamplecode.com/2012/08/android-fragment-example.html
almisoft

Я не в фрагменті, я намагаюся зробити це на onCreate a activity
kAmol

Хм, або використовувати onPause()?
almisoft

10

Ця проблема насправді була викликана NestedFragments. В основному більшість фрагментів ми розширюємо HostedFragment, який, у свою чергу, розширює CompatFragment. Наявність цих вкладених фрагментів спричинило проблеми, які врешті-решт були вирішені іншим розробником проекту.

Він робив такі речі низького рівня, як перемикання бітів, щоб зробити це робочим, тому я не надто впевнений у фактичному остаточному рішенні


Це допомогло мені вирішити мою проблему: мені довелося перенаправити onRequestPermissionsResult з батьківського фрагмента на дочірній (вкладений) фрагмент. Дякую за пораду!
Мерфі

9
 /* use the object of your fragment to call the 
 * onRequestPermissionsResult in fragment after
 * in activity and use different request Code for 
 * both Activity and Fragment */

   if (isFragment)
    mFragment.requestPermissions(permissions.toArray(new
    String[permissions.size()]),requestPermission);

   else
    ActivityCompat.requestPermissions(mActivity,permissions.toArray(new
    String[permissions.size()]),requestPermission);

6

Це спрацює ..

@Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

супер реалізація називає реалізацію фрагментів не hte frame
Мохаммед Яхіа

5

Якщо ви викликаєте цей код з фрагмента, у нього є власний метод requestPermissions.

Тож базовим поняттям є: Якщо ви перебуваєте в діяльності, тоді телефонуйте

ActivityCompat.requestPermissions(this,
                            permissionsList,
                            permissionscode);

а якщо у Фрагменті, просто зателефонуйте

requestPermissions(permissionsList,
                            permissionscode);

1
Потрібен рівень API 23 ... На попередньому використанні FragmentCompat.requestPermissions().
Мінас Міна

5

У мене була подібна проблема, за винятком того, що я натискав кнопку, щоб здійснити дзвінок, який запускає callIntent. Спочатку я перевірив дозвіл, якщо його не надано, я прошу дозволу, а наRequestPermissionResult я закликаю дозвіл на чек і дзвоню ще раз.

 @Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    switch (requestCode) {
        case Constants.PERMISSIONS_REQUEST_CALL_PHONE: {
            if ( grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                checkPermissionsAndCall();
            }
        }
    }
}

public void checkPermissionsAndCall(){
    if (Build.VERSION.SDK_INT > 22) {
        if(ContextCompat.checkSelfPermission(getContext(),
                Manifest.permission.CALL_PHONE)
                != PackageManager.PERMISSION_GRANTED){
            requestPermissions( new String[]{Manifest.permission.CALL_PHONE}, Constants.PERMISSIONS_REQUEST_CALL_PHONE);
        }
        else{
            callIntent();
        }
    }
}


2

Перш ніж перевірити все відповідно до вищезазначених відповідей, переконайтесь, що код запиту не дорівнює 0 !!!

перевірити код onRequestPermissionsResult () у FragmentActivity.java:

public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
        @NonNull int[] grantResults) {
    int index = (requestCode>>16)&0xffff;
    if (index != 0) {
        index--;

        String who = mPendingFragmentActivityResults.get(index);
        mPendingFragmentActivityResults.remove(index);
        if (who == null) {
            Log.w(TAG, "Activity result delivered for unknown Fragment.");
            return;
        }
        Fragment frag = mFragments.findFragmentByWho(who);
        if (frag == null) {
            Log.w(TAG, "Activity result no fragment exists for who: " + who);
        } else {
            frag.onRequestPermissionsResult(requestCode&0xffff, permissions, grantResults);
        }
    }
}

2
private void showContacts() {
    if (getActivity().checkSelfPermission(Manifest.permission.READ_CONTACTS)
        != PackageManager.PERMISSION_GRANTED) {
        requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, PERMISSIONS_REQUEST_READ_CONTACTS);
    } else {
        doShowContacts();
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    if (requestCode == PERMISSIONS_REQUEST_READ_CONTACTS && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        doShowContacts();
    }
}

2

У мене є дивовижне рішення, щоб досягти цього зробити BaseActivity, як це.

public class BaseActivity extends AppCompatActivity {

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // Thread.setDefaultUncaughtExceptionHandler(new MyExceptionHandler(this));


}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
    switch (requestCode) {
        case 1: {
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                CustomToast.getInstance().setCustomToast("Now you can share the Hack.");

            } else {
                Toast.makeText(this, "Permission denied to read your External storage", Toast.LENGTH_SHORT).show();
            }
        }
    }
}

}

Тепер ви можете зателефонувати до коду, щоб запитати дозволу, як це

 ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);

Тепер кожен раз, коли це відбувається де завгодно, будь то у вашому фрагменті чи в будь-якій діяльності, називатиметься базовою активністю.

Дякую


1

Можна використовувати requestPermissions(PERMISSIONS, MULTIPLE_PERMISSIONS_CODE);. Не використовуйте FragmentCompat, якщо ви використовуєте v4.


Прошу уточнити, чому.
Розміщення

1

Деталі

  • Котлін 1.2.70
  • зареєстровано у minSdkVersion 19
  • Android студія 3.1.4

Алгоритм

модуль - камера, розташування, ....

  1. Перевірте, чи функція hasSystemFeature (якщо в телефоні існує модуль )
  2. Перевірте, чи має користувач доступ до модуля
  3. Надіслати запит на отримання дозволу (попросіть користувача дозволити використання модуля )

Особливості

  1. Робота з діяльністю та фрагментами
  2. Має лише один результат відповіді
  3. Можна перевірити кілька модулів в одному запиті

Рішення

class PermissionType(val manifest_permission: String, val packageManager: String) {
    object Defined {
        val camera = PermissionType(Manifest.permission.CAMERA, PackageManager.FEATURE_CAMERA)
        val currentLocation = PermissionType(Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.FEATURE_LOCATION_GPS)
    }
}

class  Permission {

    enum class PermissionResult {
        ACCESS_ALLOWED, ACCESS_DENIED, NO_SYSTEM_FEATURE;
    }

    interface ManagerDelegate {
        fun permissionManagerDelegate(result: Array<Pair<String, PermissionResult>>)
    }

    class Manager internal constructor(private val delegate: ManagerDelegate?) {

        private var context: Context? = null
        private var fragment: Fragment? = null
        private var activity: AppCompatActivity? = null
        private var permissionTypes: Array<PermissionType> = arrayOf()
        private val REQUEST_CODE = 999
        private val semaphore = Semaphore(1, true)
        private var result: Array<Pair<String, PermissionResult>> = arrayOf()


        constructor(permissionType: PermissionType, delegate: ManagerDelegate?): this(delegate) {
            permissionTypes = arrayOf(permissionType)
        }

        constructor(permissionTypes: Array<PermissionType>, delegate: ManagerDelegate?): this(delegate) {
            this.permissionTypes = permissionTypes
        }

        init {
            when (delegate) {
                is Fragment -> {
                    this.fragment = delegate
                    this.context = delegate.context
                }

                is AppCompatActivity -> {
                    this.activity = delegate
                    this.context = delegate
                }
            }
        }

        private fun hasSystemFeature(permissionType: PermissionType) : Boolean {
            return context?.packageManager?.hasSystemFeature(permissionType.packageManager) ?: false
        }

        private fun hasAccess(permissionType: PermissionType) : Boolean {
            return if (Build.VERSION.SDK_INT < 23) true else {
                context?.checkSelfPermission(permissionType.manifest_permission) == PackageManager.PERMISSION_GRANTED
            }
        }

        private fun sendRequest(permissionTypes: Array<String>) {

            if (fragment != null) {
                fragment?.requestPermissions(permissionTypes, REQUEST_CODE)
                return
            }

            if (activity != null){
                ActivityCompat.requestPermissions(activity!!, permissionTypes, REQUEST_CODE)
            }
        }

        fun check() {

            semaphore.acquire()
            AsyncTask.execute {
                var permissionsForSendingRequest: Array<String> = arrayOf()
                this.result = arrayOf()

                for (it in permissionTypes) {
                    if (!hasSystemFeature(it)) {
                        result += Pair(it.manifest_permission, PermissionResult.NO_SYSTEM_FEATURE)
                        continue
                    }

                    if (hasAccess(it)) {
                        result += Pair(it.manifest_permission, PermissionResult.ACCESS_ALLOWED)
                    } else {
                        permissionsForSendingRequest += it.manifest_permission
                    }
                }

                if (permissionsForSendingRequest.isNotEmpty()) {
                    sendRequest(permissionsForSendingRequest)
                } else {
                    delegate?.permissionManagerDelegate(result)
                }
            }
        }

        fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
            when (requestCode) {
                REQUEST_CODE -> {
                    if (grantResults.isEmpty()) {
                        return
                    }
                    for ((i,permission) in permissions.withIndex()) {
                        for (item in this.permissionTypes) {
                            if (permission == item.manifest_permission && i < grantResults.size) {
                                result += if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                                    Pair(item.manifest_permission, PermissionResult.ACCESS_ALLOWED)
                                } else {
                                    Pair(item.manifest_permission, PermissionResult.ACCESS_DENIED)
                                }
                                break
                            }
                        }
                    }
                    delegate?.permissionManagerDelegate(result)
                }
            }
            semaphore.release()
        }
    }
}

Використання в діяльності (у фрагменті те саме)

class BaseActivity : AppCompatActivity(), Permission.ManagerDelegate {

    private lateinit var permissionManager: Permission.Manager

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.base_activity)

        permissionManager = Permission.Manager(arrayOf(PermissionType.Defined.camera, PermissionType.Defined.currentLocation), this)
        permissionManager.check()
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        permissionManager.onRequestPermissionsResult(requestCode, permissions, grantResults)
    }


    override fun permissionManagerDelegate(result: Array<Pair<String, Permission.PermissionResult>>) {
        result.forEach {
            println("!!! ${it.first} ${it.second}")
//            when (it.second) {
//                Permission.PermissionResult.NO_SYSTEM_FEATURE -> {
//                }
//
//                Permission.PermissionResult.ACCESS_DENIED  -> {
//                }
//
//                Permission.PermissionResult.ACCESS_ALLOWED -> {
//                }
//            }
        }
    }
}

1

Тут я хочу показати свій код, як мені це вдалося.

public class CheckPermission {

public Context context;

public static final int PERMISSION_REQUEST_CODE =  200;

public CheckPermission(Context context){
    this.context = context;
}

public boolean isPermissionGranted(){
    int read_contact = ContextCompat.checkSelfPermission(context.getApplicationContext() , READ_CONTACTS);
    int phone = ContextCompat.checkSelfPermission(context.getApplicationContext() , CALL_PHONE);

    return read_contact == PackageManager.PERMISSION_GRANTED && phone == PackageManager.PERMISSION_GRANTED;
   }
}

Тут у цьому класі я хочу перевірити наданий дозвіл чи ні. Чи не тоді я буду називати дозвіл від мого MainActivity, як

public void requestForPermission() {
       ActivityCompat.requestPermissions(MainActivity.this, new String[]    {READ_CONTACTS, CALL_PHONE}, PERMISSION_REQUEST_CODE);
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode) {
        case PERMISSION_REQUEST_CODE:
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (shouldShowRequestPermissionRationale(ACCESS_FINE_LOCATION)) {
                    showMessageOKCancel("You need to allow access to both the permissions",
                            new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                                        requestPermissions(new String[]{Manifest.permission.READ_CONTACTS, Manifest.permission.CALL_PHONE},
                                                PERMISSION_REQUEST_CODE);
                                    }
                                }
                            });
                    return;
                }
            }
    }
}

Тепер у методі onCreate потрібно викликати функцію requestForPermission ().

Це все. Так само ви можете запитувати декілька дозволів одночасно.


1

ОНОВЛЕННЯ: побачив чужу відповідь про виклик super.onRequestPermissionResult()у "Діяльності", що виправляє проблему з кодом запиту, яку я згадував, і викликає фрагмент onRequestPermissionResult.

ігноруйте цей матеріал:

Для мене це викликало onRequestPermissionResultактивність, незважаючи на те, що я дзвонив fragment.requestPermission(...), але НЕ повернув результат неправильним запитомCode (111 перетворився на 65647, чому я ніколи не дізнаюся).

На щастя, це єдиний дозвіл, який ми вимагаємо на цьому екрані, тому я просто ігнорую код запиту (не встигаю з’ясувати, чому це зараз не правильно)


Додайте 65536 та 111, і ви отримаєте. Це через бітові маски. Дивіться деякі теми.
CoolMind

0

Я також зіткнувся з проблемою, що навіть якщо ви зателефонували на правильний запитPermissions, ви все одно можете мати цю проблему. Проблема полягає в тому, що батьківська діяльність може змінити цей метод, не викликаючи супер. Додайте супер, і це буде виправлено.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.