Ранее я рассказывал об относительно малоизвестной и ныне удалённой строке-заполнителе в Android, использовавшейся в качестве пасхалки. Это был выдуманный оператор сотовой связи под названием El Telco Loco. Сегодня я расскажу о методах и других частях публично доступного Android API, которые могут показаться больше смешными, чем полезными. Это пасхальные яйца, шутки, видимые только разработчикам приложений для Android, но не обычным пользователям.

ActivityManager.isUserAMonkey()

(ссылка)

Хоть поначалу это может и показаться шуткой, возвращающей true, если UI «на данный момент пользуется обезьяна» и без каких-то дополнительных подробностей в документации, вероятно, этот метод — один из самых полезных в моём посте.

Он связан с UI Exerciser Monkey — инструментом Android-разработчика, имитирующим случайные последовательности пользовательского ввода для нагрузочного тестирования приложений. То есть этот метод возвращает булево значение, определяющее, используется ли в данный момент Monkey.

Появление такого метода, предназначенного для обнаружения работы Monkey, обязано событию, произошедшему в процессе разработки Android. Вот цитата из книги Androids: The Team that Built the Android Operating System:

Однажды я зашёл в monkey-лабораторию и услышал голос: «911, что у вас произошло?» Из-за этой ситуации Дианна добавила в API новую функцию isUserAMonkey(), которая используется ограничения действий, которые обезьяны не могут делать во время тестов (в том числе звонить по телефону и выполнять сброс устройства).

И в самом деле, при передаче случайных и непредсказуемых входных данных в приложение нужно каким-то образом блокировать те части приложения, которые могут неожиданным образом влиять на реальный мир. Например, звонить в спасательные службы. Поэтому и была реализована isUserAMonkey, которая затем добралась до публичного API в Android 2.2 Froyo (API 8).

UserManager.isUserAGoat()

(ссылка)

Этот метод уже ближе к шуточному. В документации разработчика говорится, что он «используется для определения того, склонен ли делающий этот вызов пользователь к телепортации», что само по себе, скорее всего, является отсылкой к скрытому столбцу в диспетчере задач Chrome, показывающему, сколько коз телепортировал процесс браузера.

Впервые метод появился в Android 4.2 (API 17); изначально он просто возвращал false. Однако в Android 5.0 Lollipop (API 21) его описание было изменено на «автоматическая идентификация коз при помощи современной технологии распознавания коз». В начале того же года была выпущена игра Goat Simulator, ставшая доступной для Android в сентябре, в процессе разработки Lollipop, поэтому теперь этот метод определял наличие на устройстве установленной Android-версии Goat Simulator:

public boolean isUserAGoat() {
	return mContext.getPackageManager()
		.isPackageAvailable("com.coffeestainstudios.goatsimulator");
}

В Android 11 (API 30) его снова изменили так, чтобы приложения для API 30 и выше при его вызове всегда возвращали false. Согласно документации разработчика, это было сделано «для защиты личной жизни коз».

if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R) {
	return false;
}

Также в Android 11 появилось разрешение QUERY_ALL_PACKAGES, то есть приложения, разрабатываемые под целевую платформу Android 11, не могут без этого разрешения запрашивать информацию о других приложениях через PackageManager. Поэтому разумно будет тоже огородить этот метод, чтобы не допускать утечки информации о других приложениях, установленных на устройстве пользователя, даже в качестве шутки.

UserManager.DISALLOW_FUN

(ссылка)

Эта константа, относящаяся к политике устройства, была добавлена в Android 6 Marshmallow (API 23), она запрещает пользователю «радоваться». Иронично, что описание этого метода из документации разработчика очень забавно и напоминает слова, которые бы вполне могла сказать GLaDOS:

Определяет, может ли пользователь радоваться. В некоторых случаях владелец устройства может решить ограничить у пользователя чувства радости или веселья при работе с устройством.

На самом деле, это реальная политика устройства, которую владелец устройства может менять, чтобы ограничивать действия пользователя. И сторонние приложения могут привязываться к этой политике, чтобы отключать функции приложения, которые кажутся «слишком весёлыми». Не знаю ни одного стороннего приложения, которое бы использовало этот метод, а в системе Android он применяется для отключения паскалки версии Android, отображаемой при нажатии на метку версии в настройках.

Учитывая то, что «весёлые» пасхалки наподобие мини-игры с динозавром в Google Chrome становятся отвлекающим фактором, некоторые учреждения, например, школы, стремятся отключать их на зарегистрированных устройствах (см. issue Chromium 41159706); возможно, пасхалка версии Android тоже может кого-то отвлекать.

Chronometer.isTheFinalCountdown()

(ссылка)

У класса Chronometer есть новый метод, называющийся isTheFinalCountdown; он был добавлен в Android 8 Oreo (API 26). При вызове он отправляет намерение (intent) открыть YouTube-видео The Final Countdown группы Europe.

Серьёзно, именно это он и делает:

try {
	getContext().startActivity(
		new Intent(Intent.ACTION_VIEW, Uri.parse("https://youtu.be/9jK-NcRmVcw"))
			.addCategory(Intent.CATEGORY_BROWSABLE)
			.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT
				| Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT));
	return true;
} catch (Exception e) {
	return false;
}

Чудесно.

PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_JAZZHAND

(ссылка)

Эта константа была добавлена в Android 2.3 Gingerbread (API 8), она используется для описания устройства, поддерживающего отслеживание пяти одновременных сенсорных касаний. Имя константы — отсылка к Jazz hands.

Log.wtf()

(ссылка)

Согласно документации разработчика, WTF расшифровывается, как «What a Terrible Failure» (ну да…). Этот метод предназначен для логгинга событий, которые не должны происходить никогда. Он выполняет логгинг сообщений на уровне утверждения (assertion).

AdapterViewFlipper.fyiWillBeAdvancedByHostKThx()

(ссылка)

Это метод со странно-забавным неформальным именем, которое, возможно, появилось, когда разработчик не смог придумать нормальное имя. В результате оно попало в публичный Android API в Android 3.0 Honeycomb (API 11). Метод вызывается AppWidgetHost при переключении представлений внутри объекта AdapterViewFlipper.

И в самом деле, придумывание имён — одна из двух самых сложных задач в computer science. Две другие — это ошибки смещения на единицу и инвалидация кэша.

IBinder.TWEET_TRANSACTION

(ссылка)

Система Android Binder используется для выполнения IPC, а транзакции дифференцируются при помощи различных типов, один из которых — это… TWEET_TRANSACTION. Он был добавлен в Android 3.2 Honeycomb (API 13); заявляется, что он используется для отправки твита целевому объекту.

На самом деле, он ничего не делает, не говоря уже об отправке твитов. В документации написано, что сообщения имеют ограничение в 130 символов, что соответствует старому ограничению на количество символов в Twitter.

IBinder.LIKE_TRANSACTION

(ссылка)

Аналогично, в Android 4.0.3 ICS (API 15) был добавлен новый тип транзакций LIKE_TRANSACTION. Он используется, чтобы сообщить приложению, что вызывающему оно нравится; счётчика лайков нет, но утверждается, что отправка таких транзакций повысит самооценку приложения.

SensorManager.SENSOR_TRICORDER

(ссылка)

Должен признаться: я не знаю, что такое Tricorder, но похоже, это выдуманное устройство из «Звёздного пути» (Star Trek). Эта константа была «добавлена» в Android 1.0 (то есть, скорее всего, она присутствовала ещё до первого официального релиза Android).

Константы SENSOR_* в SensorManager считаются устаревшими, начиная с API level 15; их заменил класс Sensor, не содержащий эквивалентной отсылки к Tricorder. К сожалению.

SensorManager.GRAVITY_*

(ссылка)

В классе SensorManager есть множество констант, хранящих ускорение силы тяжести различных тел нашей Солнечной системы, от GRAVITY_SUN до GRAVITY_PLUTO. Хотя можно поспорить, полезны ли в реальных ситуациях какие-то из них, кроме GRAVITY_EARTH, некоторые из них стали забавными шутками.

GRAVITY_DEATH_STAR_I хранит ускорение силы тяжести первой Звезды смерти в единицах СИ (в документации названных единицами Империи). Это отсылка к «Звёздным войнам».

GRAVITY_THE_ISLAND хранит ускорение силы тяжести на «острове». Похоже, это отсылка к Острову из телесериала «Остаться в живых» (Lost).

<blink>

Последний и особенно безумный пример. Вы знали, что в системе компоновки представлений Android есть тэг под названием <blink>? А он существует:

// [TAG_1995 = "blink"]
if (name.equals(TAG_1995)) {
	// Let's party like it's 1995!
	return new BlinkLayout(context, attrs);
}

Он заставляет мигать любой дочерний элемент, обёрнутый в него, как это делал старый тэг HTML <blink>. Похоже, он совершенно не задокументирован в справке Android Developer и был добавлен в коммите 2011 года с заголовком «Повышение степени соответствия LayoutInflater» (ага…). Он всё ещё присутствует в основной ветке AOSP.

Остаётся под вопросом, стоит ли его использовать.