Урок 101. Создаем свой ContentProvider

Обсуждение уроков
Аватара пользователя
damager82
Администратор
Сообщения: 1383
Зарегистрирован: 07 янв 2012, 11:32
Контактная информация:

Урок 101. Создаем свой ContentProvider

Сообщение damager82 » 06 авг 2012, 23:00

В этом уроке:
- создаем свой ContentProvider


Click here to read this article!
Последний раз редактировалось damager82 23 май 2017, 22:04, всего редактировалось 13 раз.
Добро пожаловать на форум сайта StartAndroid
ИзображениеИзображение

Аватара пользователя
neoksi
Сообщения: 712
Зарегистрирован: 26 июл 2012, 10:42
Контактная информация:

Re: Урок 101. Создаем свой ContentProvider

Сообщение neoksi » 16 авг 2012, 11:21

Спасибо, выцедил пару улучшений для своего ContentProvider'а, который был недавно мной написан.

У меня возник вопрос, в своем проекте я не могу использовать CursorAdapter, так как мне необходимо наполнять адаптер из нескольких курсоров. Возможно ли отловить событие обновления курсора и назначить свой обработчик? (к примеру как мы отлавливаем событие нажатия кнопки, но только для курсора).

Аватара пользователя
rezak90
Сообщения: 3422
Зарегистрирован: 26 июн 2012, 13:22
Откуда: UA
Контактная информация:

Re: Урок 101. Создаем свой ContentProvider

Сообщение rezak90 » 27 авг 2012, 13:55

Что то не въехал малёха. Не вижу большой разницы между ContentProvider'ом и SQLiteOpenHelper'ом. Всё что мы реализовываем (методы insert update delete и т.д.) можно реализовать и в SQLiteOpenHelper. Единственно что я понял так это что мы можем обратится из своего приложения к любой бд, я ж правильно понял?
R.id.team
Политика на форуме запрещена

Аватара пользователя
neoksi
Сообщения: 712
Зарегистрирован: 26 июл 2012, 10:42
Контактная информация:

Re: Урок 101. Создаем свой ContentProvider

Сообщение neoksi » 27 авг 2012, 16:40

rezak90
ContentProvider является посредником между данными (в нашем случае это БД) и приложениями. Так же он создается в единственном экземпляре, что дает следующие преимущества:
1) Открывается только одна копия источника данных (у нас это БД sqlite);
2) Позволяет сделать механизм синхронизации отображаемой информации и информации содержащийся в источнике.

Ну это только 2 пункта, что меня заставили писать в приложении собственную реализацию контент провайдера для данных.

Аватара пользователя
rezak90
Сообщения: 3422
Зарегистрирован: 26 июн 2012, 13:22
Откуда: UA
Контактная информация:

Re: Урок 101. Создаем свой ContentProvider

Сообщение rezak90 » 27 авг 2012, 17:02

короче я так понял провайдер даёт возможность подключаться к бд более чем одному приложению? Но не понял можно ли получить данные из бд которую не знаешь (например указать имя бд и вытянуть от тудого все таблицы с полями, заведомо не зная названия таблиц и столбцов)? И ещё, можно ли присабачить провайдер и программу в одно приложение, а не как создавать в уроке.
ап, ещё вычитал что с помощу провайдеров могут общаться между собой приложения, было бы интересно на это посмотреть.
R.id.team
Политика на форуме запрещена

Аватара пользователя
neoksi
Сообщения: 712
Зарегистрирован: 26 июл 2012, 10:42
Контактная информация:

Re: Урок 101. Создаем свой ContentProvider

Сообщение neoksi » 27 авг 2012, 18:12

rezak90 писал(а):короче я так понял провайдер даёт возможность подключаться к бд более чем одному приложению?
Принципиально прав, но я бы сказал, что он дает подключиться к БД более чем одному процессу.
rezak90 писал(а):Но не понял можно ли получить данные из бд которую не знаешь (например указать имя бд и вытянуть от тудого все таблицы с полями, заведомо не зная названия таблиц и столбцов)?
Тут скорей всего вопрос в правильном построении SQL запроса.
rezak90 писал(а): И ещё, можно ли присабачить провайдер и программу в одно приложение, а не как создавать в уроке.
Лично у меня оно так и сделано в моем приложении, а ещё у меня запрещено другим приложениям, кроме моего, обращаться к моему контент провайдеру.
rezak90 писал(а): ап, ещё вычитал что с помощу провайдеров могут общаться между собой приложения, было бы интересно на это посмотреть.
Когда с ними разберешься, то такое можно организовать.

Аватара пользователя
rezak90
Сообщения: 3422
Зарегистрирован: 26 июн 2012, 13:22
Откуда: UA
Контактная информация:

Re: Урок 101. Создаем свой ContentProvider

Сообщение rezak90 » 30 авг 2012, 10:07

я так понял что getContentResolver() возвращает все провайдеры которые есть в Android'e. В общем как например вытащить все названия провайдеров которые функционируют на данный момент в системе, не зная их названия.
R.id.team
Политика на форуме запрещена

Аватара пользователя
neoksi
Сообщения: 712
Зарегистрирован: 26 июл 2012, 10:42
Контактная информация:

Re: Урок 101. Создаем свой ContentProvider

Сообщение neoksi » 30 авг 2012, 14:32

rezak90 писал(а):я так понял что getContentResolver() возвращает все провайдеры которые есть в Android'e. В общем как например вытащить все названия провайдеров которые функционируют на данный момент в системе, не зная их названия.
getContentResolver() - это интерфейс, что ищет нужного контент провайдера по Uri.

Аватара пользователя
rezak90
Сообщения: 3422
Зарегистрирован: 26 июн 2012, 13:22
Откуда: UA
Контактная информация:

Re: Урок 101. Создаем свой ContentProvider

Сообщение rezak90 » 04 сен 2012, 10:49

Уже хотел накатать сюда огромный пост по одной проблеме, как вдруг осенило))) Как то после каждого обращения к бд я всё время закрывал подключения с ней, а потом курсор получался с возвратом null и не мог понять почему так. Такой себе вопрос для рассуждения: почему каждый раз открывается новое соединение с бд и не закрывается? Не влияет ли это на производительность? И вообще правильно ли это с точки зрения архитектуры? Или я может чего то не уловил...
R.id.team
Политика на форуме запрещена

Аватара пользователя
rezak90
Сообщения: 3422
Зарегистрирован: 26 июн 2012, 13:22
Откуда: UA
Контактная информация:

Re: Урок 101. Создаем свой ContentProvider

Сообщение rezak90 » 04 сен 2012, 11:34

всё время выходит путанница с айди. Вот у меня такой адрес "ua.my.providers.Supershop/sneakers/" где sneakers - название таблицы. Если обращаюсь по адресу "ua.my.providers.Supershop/sneakers/33" то uMatcher.match(uri) возвращает мне цифру 2 всегда, мне почему то казалось что метод match возвращает то что стоит в конце или же после названия таблицы, он берёт от куда то двойку. Сам UriMatcher такой:

Код: Выделить всё

uMatcher = new UriMatcher(UriMatcher.NO_MATCH);
		uMatcher.addURI(AUTHORITY, TABLE_NAME, 1);
		uMatcher.addURI(AUTHORITY, TABLE_NAME + "/#", 2);
R.id.team
Политика на форуме запрещена

Аватара пользователя
neoksi
Сообщения: 712
Зарегистрирован: 26 июл 2012, 10:42
Контактная информация:

Re: Урок 101. Создаем свой ContentProvider

Сообщение neoksi » 04 сен 2012, 12:49

rezak90 писал(а):всё время выходит путанница с айди. Вот у меня такой адрес "ua.my.providers.Supershop/sneakers/" где sneakers - название таблицы. Если обращаюсь по адресу "ua.my.providers.Supershop/sneakers/33" то uMatcher.match(uri) возвращает мне цифру 2 всегда, мне почему то казалось что метод match возвращает то что стоит в конце или же после названия таблицы, он берёт от куда то двойку. Сам UriMatcher такой:

Код: Выделить всё

uMatcher = new UriMatcher(UriMatcher.NO_MATCH);
		uMatcher.addURI(AUTHORITY, TABLE_NAME, 1);
		uMatcher.addURI(AUTHORITY, TABLE_NAME + "/#", 2);
Он тебе правильно возвращает 2.
В методе ты делаешь:

Код: Выделить всё

            // Вычисляем какая таблица нужна. 
	    switch (uriMatcher.match(uri)){
			case 1: 
				uTable = TABLE_NAME;
                        break;
			case 2: 
				uTable = TABLE_NAME;
				// Получаем id необходимой строки				
				uID = uri.getLastPathSegment();
                        break;
             }
И таким образом получаешь нужный ID.

Аватара пользователя
rezak90
Сообщения: 3422
Зарегистрирован: 26 июн 2012, 13:22
Откуда: UA
Контактная информация:

Re: Урок 101. Создаем свой ContentProvider

Сообщение rezak90 » 04 сен 2012, 13:23

а понял, ошибка была в самом запросе, нужно было не "ua.my.providers.Supershop/sneakers/33" а просто "ua.my.providers.Supershop/sneakers", то есть не ставить палку после названия таблицы, а так UriMatcher определял как айди столбца, а не всю таблицу.
R.id.team
Политика на форуме запрещена

htk
Сообщения: 5
Зарегистрирован: 10 июл 2012, 10:09

Re: Урок 101. Создаем свой ContentProvider

Сообщение htk » 17 ноя 2012, 16:16

У меня возник вопрос, на который я никак не могу найти ответ, у меня довольно большая структура БД, и порядка 15 таблиц, мне необходимо писать для каждой своего провайдера, либо лепить все в один, и использовать кейсы?

Ant
Сообщения: 9
Зарегистрирован: 05 дек 2012, 14:06

Re: Урок 101. Создаем свой ContentProvider

Сообщение Ant » 15 фев 2013, 10:02

и ещё один вопрос: если кто-то сможет разобраться с запросами к моему провайдеру, то без проблем сможет курочить мою БД своим приложением? как от этого защищаться?

Dangreon
Сообщения: 41
Зарегистрирован: 01 янв 2013, 15:52

Re: Урок 101. Создаем свой ContentProvider

Сообщение Dangreon » 06 мар 2013, 11:02

Я не знаю, заметили или нет те кто смотрел этот урок, в отличие от SQLiteOpenHelper'а, обращение к базе при помощи своего ContentProvider'а позволяет
делать оповещения о сделанных изменениях. Эти оповещения в дальнейшем можно обрабатывать. Код где оповещения:
getContext().getContentResolver().notifyChange(uri, null);

gh-gh
Сообщения: 2
Зарегистрирован: 24 апр 2013, 17:16

Re: Урок 101. Создаем свой ContentProvider

Сообщение gh-gh » 25 апр 2013, 09:01

"У нас тут получилось, что имя таблицы в БД совпало с path в Uri. Это вовсе необязательно, они могут быть разными."
Если не ошибаюсь, если они будут разными, то в вашем примере будет IllegalArgumentException("Wrong URI: " + uri);
Потому что uri придет вида "content://ru.startandroid.providers.AdressBook/contacts" исходя из этой строчки
public static final Uri CONTACT_CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + CONTACT_PATH);
а UriMatcher будет сравнивать её с чем нибудь вроде "content://ru.startandroid.providers.AdressBook/contacts_db" изходя из этого:
uriMatcher.addURI(AUTHORITY, CONTACT_TABLE, URI_CONTACTS);
Или я не правильно что то понял, но у меня не работает.

Аватара пользователя
damager82
Администратор
Сообщения: 1383
Зарегистрирован: 07 янв 2012, 11:32
Контактная информация:

Re: Урок 101. Создаем свой ContentProvider

Сообщение damager82 » 29 апр 2013, 11:23

gh-gh писал(а):"У нас тут получилось, что имя таблицы в БД совпало с path в Uri. Это вовсе необязательно, они могут быть разными."
Если не ошибаюсь, если они будут разными, то в вашем примере будет IllegalArgumentException("Wrong URI: " + uri);
Верно, у меня ошибка в уроке. Вместо
[syntax=java] uriMatcher.addURI(AUTHORITY, CONTACT_TABLE, URI_CONTACTS);
uriMatcher.addURI(AUTHORITY, CONTACT_TABLE + "/#", URI_CONTACTS_ID);[/syntax]
Надо
[syntax=java] uriMatcher.addURI(AUTHORITY, CONTACT_PATH, URI_CONTACTS);
uriMatcher.addURI(AUTHORITY, CONTACT_PATH+ "/#", URI_CONTACTS_ID);[/syntax]

Спасибо, что написали об этом!
Добро пожаловать на форум сайта StartAndroid
ИзображениеИзображение

Mill666
Сообщения: 4
Зарегистрирован: 30 апр 2013, 10:50

Re: Урок 101. Создаем свой ContentProvider

Сообщение Mill666 » 30 апр 2013, 10:57

Здравствуйте =)
вроде бы все делаю по уроку, однако программа при запуске сразу выдает ошибку =(

Код: Выделить всё

04-30 14:53:15.150: D/dalvikvm(2455): GC_CONCURRENT freed 56K, 7% free 2803K/3004K, paused 18ms+5ms, total 72ms
04-30 14:53:15.150: D/AndroidRuntime(2455): Shutting down VM
04-30 14:53:15.150: W/dalvikvm(2455): threadid=1: thread exiting with uncaught exception (group=0x40a71930)
04-30 14:53:15.170: E/AndroidRuntime(2455): FATAL EXCEPTION: main
04-30 14:53:15.170: E/AndroidRuntime(2455): java.lang.RuntimeException: Unable to start activity ComponentInfo{ru.startandroid.develop.contprovclient/ru.startandroid.develop.contprovclient.MainActivity}: java.lang.SecurityException: Permission Denial: opening provider ru.startandroid.develop.contentprovider.MyContactProvider from ProcessRecord{41718cd8 2455:ru.startandroid.develop.contprovclient/u0a10047} (pid=2455, uid=10047) that is not exported from uid 10046
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2180)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.app.ActivityThread.access$600(ActivityThread.java:141)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.os.Handler.dispatchMessage(Handler.java:99)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.os.Looper.loop(Looper.java:137)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.app.ActivityThread.main(ActivityThread.java:5041)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at java.lang.reflect.Method.invokeNative(Native Method)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at java.lang.reflect.Method.invoke(Method.java:511)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at dalvik.system.NativeStart.main(Native Method)
04-30 14:53:15.170: E/AndroidRuntime(2455): Caused by: java.lang.SecurityException: Permission Denial: opening provider ru.startandroid.develop.contentprovider.MyContactProvider from ProcessRecord{41718cd8 2455:ru.startandroid.develop.contprovclient/u0a10047} (pid=2455, uid=10047) that is not exported from uid 10046
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.os.Parcel.readException(Parcel.java:1425)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.os.Parcel.readException(Parcel.java:1379)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.app.ActivityManagerProxy.getContentProvider(ActivityManagerNative.java:2545)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.app.ActivityThread.acquireProvider(ActivityThread.java:4462)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.app.ContextImpl$ApplicationContentResolver.acquireUnstableProvider(ContextImpl.java:2002)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.content.ContentResolver.acquireUnstableProvider(ContentResolver.java:1101)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.content.ContentResolver.query(ContentResolver.java:356)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.content.ContentResolver.query(ContentResolver.java:315)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at ru.startandroid.develop.contprovclient.MainActivity.onCreate(MainActivity.java:29)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.app.Activity.performCreate(Activity.java:5104)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	... 11 more


exFoxer
Сообщения: 1
Зарегистрирован: 18 мар 2013, 14:47

Re: Урок 101. Создаем свой ContentProvider

Сообщение exFoxer » 17 май 2013, 16:50

Mill666 писал(а):Здравствуйте =)
вроде бы все делаю по уроку, однако программа при запуске сразу выдает ошибку =(

Код: Выделить всё

04-30 14:53:15.150: D/dalvikvm(2455): GC_CONCURRENT freed 56K, 7% free 2803K/3004K, paused 18ms+5ms, total 72ms
04-30 14:53:15.150: D/AndroidRuntime(2455): Shutting down VM
04-30 14:53:15.150: W/dalvikvm(2455): threadid=1: thread exiting with uncaught exception (group=0x40a71930)
04-30 14:53:15.170: E/AndroidRuntime(2455): FATAL EXCEPTION: main
04-30 14:53:15.170: E/AndroidRuntime(2455): java.lang.RuntimeException: Unable to start activity ComponentInfo{ru.startandroid.develop.contprovclient/ru.startandroid.develop.contprovclient.MainActivity}: java.lang.SecurityException: Permission Denial: opening provider ru.startandroid.develop.contentprovider.MyContactProvider from ProcessRecord{41718cd8 2455:ru.startandroid.develop.contprovclient/u0a10047} (pid=2455, uid=10047) that is not exported from uid 10046
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2180)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.app.ActivityThread.access$600(ActivityThread.java:141)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.os.Handler.dispatchMessage(Handler.java:99)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.os.Looper.loop(Looper.java:137)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.app.ActivityThread.main(ActivityThread.java:5041)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at java.lang.reflect.Method.invokeNative(Native Method)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at java.lang.reflect.Method.invoke(Method.java:511)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at dalvik.system.NativeStart.main(Native Method)
04-30 14:53:15.170: E/AndroidRuntime(2455): Caused by: java.lang.SecurityException: Permission Denial: opening provider ru.startandroid.develop.contentprovider.MyContactProvider from ProcessRecord{41718cd8 2455:ru.startandroid.develop.contprovclient/u0a10047} (pid=2455, uid=10047) that is not exported from uid 10046
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.os.Parcel.readException(Parcel.java:1425)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.os.Parcel.readException(Parcel.java:1379)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.app.ActivityManagerProxy.getContentProvider(ActivityManagerNative.java:2545)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.app.ActivityThread.acquireProvider(ActivityThread.java:4462)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.app.ContextImpl$ApplicationContentResolver.acquireUnstableProvider(ContextImpl.java:2002)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.content.ContentResolver.acquireUnstableProvider(ContentResolver.java:1101)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.content.ContentResolver.query(ContentResolver.java:356)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.content.ContentResolver.query(ContentResolver.java:315)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at ru.startandroid.develop.contprovclient.MainActivity.onCreate(MainActivity.java:29)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.app.Activity.performCreate(Activity.java:5104)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)
04-30 14:53:15.170: E/AndroidRuntime(2455): 	... 11 more

У меня была похожая ошибка.
Помогло добавить в тег <provider> манифеста строку:
android:exported="true"

Мой тег <provider> теперь выглядит так:
<provider
android:name="MyContactsProvider"
android:authorities="ru.startandroid.providers.AdressBook"
android:exported="true" >
</provider>

Oleg_Sl
Сообщения: 4
Зарегистрирован: 31 июл 2013, 11:09
Откуда: Беларусь, г.Минск

Re: Урок 101. Создаем свой ContentProvider

Сообщение Oleg_Sl » 16 сен 2013, 14:51

Ant писал(а):и ещё один вопрос: если кто-то сможет разобраться с запросами к моему провайдеру, то без проблем сможет курочить мою БД своим приложением? как от этого защищаться?
В AndroidManifest.xml указываем exported = false. При этом провайдер должен быть объявлен в самом приложении, а не как в уроке отдельно.

Код: Выделить всё

<provider
            android:name="[i]provider_name[/i]"
            android:authorities="[i]provider_authorities[/i]"
            android:exported="false">
       </provider>
Цитата из доков:
android:exported
Whether the content provider is available for other applications to use:
true: The provider is available to other applications. Any application can use the provider's content URI to access it, subject to the permissions specified for the provider.
false: The provider is not available to other applications. Set android:exported="false" to limit access to the provider to your applications. Only applications that have the same user ID (UID) as the provider will have access to it.
The default value is "true" for applications that set either android:minSdkVersion or android:targetSdkVersion to "16" or lower. For applications that set either of these attributes to "17" or higher, the default is "false".

You can set android:exported="false" and still limit access to your provider by setting permissions with the permission attribute.
Значение свойства exported определяет, доступен ли provider из других приложений.
true: provider доступен из других приложений через URI.
false: provider не доступен из других приложений. При это доступ из приложений с одинаковым user ID (подпись автора???) сохраняется.
Самое интересное: для приложений с API <= 16 значение по умолчанию "true", для API > 16 -- "false".

Источник: http://developer.android.com/guide/topi ... ement.html.

Ответить