Как я играл в Шерлок Хомса или как сделать, чтобы системное приложение не падало с ошибкой

от автора

В своей программе я использую вызов настроек телефона.

Intent intent = new Intent(Settings.ACTION_PRINT_SETTINGS); startActivity(intent);

Это просьба открыть нужное место в системных настройках телефона

Торопыги могут сказать, что я забыл этот вызов взять в try-catch и будут не правы.

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

Телефон открывает список всех установленных служб как и положено.

А вот после клика по имени любой службы, даже по службе от самого андроида получаем креш.

Скрытый текст

Под спойлером скриншоты

Но такая глобальная ошибка не могла остаться в релизе. Если мы попробуем попасть в настройки штатным путем (свап по экрану сверху — шестеренка — искать печать — и далее)

Скрытый текст

То все работает. Но что это такое ? Внешний вид разный !

Получается вендор не стал полностью переделывать кастомизировать штатные настройки так как есть альтернатива от него.

Первая мысль надо искать кастомный интент (для торопыг Ошибка там использован штатный)

Начинаю гуглить про Realme UI и какие нибудь кастомные интенты с печатью — пусто. Про Color OS — пусто.

Полное не понимание, а куда дальше копать.

Решаю посмотреть пакеты.

> adb shell pm list packages | grep setting  package:com.android.settings.intelligence package:com.oplus.wirelesssettings package:com.android.settings package:com.android.providers.settings  >adb shell pm list packages | grep print   package:com.google.android.printservice.recommendation package:com.android.systemui.overlay.fingerprint.anim.lgsy package:com.android.systemui.overlay.fingerprint.anim.jslz package:com.android.systemui.overlay.fingerprint.anim.jhsy package:com.android.printspooler package:com.android.systemui.overlay.fingerprint.anim.xklc package:com.android.systemui.overlay.fingerprint.anim.ccyh package:com.android.systemui.overlay.fingerprint.anim.nlgs package:com.smart.printer.print.photos.documents.printing.pictures package:com.android.systemui.overlay.fingerprint.anim.tyjw

Идей не добавляется. Но ВОТ есть же гдето-код, который работает. Но ничего похожего на настройки от самого реалми не видно.

!!! Так как узнать какое приложение на топе стека активити ? гуглим

adb shell dumpsys window | grep Focused.
  mTopFocusedDisplayId=0   mFocusedApp=ActivityRecord{37325a8 u0 ru.a402d.printservice/.ui.MainActivity t4128}       mLastFocusedRootTask=Task{a1d27a7 #4128 type=standard A=10319:ru.a402d.printservice}     mFocusedWindow=Window{22f4af7 u0 Application Error: com.android.settings}     DO DUMP StrategyManager : { StrategyIgnoreSleepKey StrategyShutdown StrategyLaunchIntercomCustom StrategyCustomizeIgnoreVirtualKey StrategyUnusedPhoneDetection StrategyBlackscreenshot StrategyPowerKeyEndCall StrategyDisableBottomKey StrategyVolumeKeyLaunchCamera StrategyIngoreKeyInFocusedWindow}     mQueueingInterceptorsCopy : [120:com.android.server.policy.KeyLongPressBaseStrategy$1@64b501c, 130:com.android.server.policy.StrategyCustomizeIgnoreVirtualKey$1@9f7c21a, 170:com.android.server.policy.StrategyDisableBottomKey$2@221d425, 190:com.android.server.policy.StrategyIngoreKeyInFocusedWindow$1@a8c9fa]     mDispatchingInterceptorsCopy : [120:com.android.server.policy.KeyLongPressBaseStrategy$1@64b501c, 130:com.android.server.policy.StrategyCustomizeIgnoreVirtualKey$1@9f7c21a, 170:com.android.server.policy.StrategyDisableBottomKey$2@221d425, 190:com.android.server.policy.StrategyIngoreKeyInFocusedWindow$1@a8c9fa]   mFocusedApp=ActivityRecord{461677f u0 com.android.printspooler/.ui.settings.SettingsEntranceActivity t4127}       mLastFocusedRootTask=Task{9e02046 #4127 type=standard A=1000:com.android.settings.root}     mFocusedWindow=Window{f727c67 u0 com.android.printspooler/com.android.printspooler.ui.settings.SettingsEntranceActivity}   mTopFocusedDisplayId=0

Оказывается из настроек мы незаметно для себя попадаем в спулер печати com.android.printspooler

А что же тогда в его манифесте ? Будем смотреть

adb shell pm path com.android.printspooler             package:/system_ext/app/PrintSpooler/PrintSpooler.apk

Узнали где лежит, теперь скачаем к себе

adb pull /system_ext/app/PrintSpooler/PrintSpooler.apk     

По быстрому заглянуть в манифест приложения, можно просто открыв apk в android studio.

        <activity             android:theme="@ref/0x7f11002a"             android:label="@ref/0x7f100135"             android:name="com.android.printspooler.ui.settings.SettingsEntranceActivity"             android:exported="true"             android:screenOrientation="-1"             android:configChanges="0x40003dfe"             android:windowSoftInputMode="0x22">  .....              <intent-filter                 android:priority="1">                  <action                     android:name="android.settings.ACTION_PRINT_SETTINGS" />                  <category                     android:name="android.intent.category.DEFAULT" />             </intent-filter>     ...                    </activity>

Оказывается нет ни какого специального интента.

Часть вторая. Как вызвать нужный компонент

И начнем мы ее решать с модификации своего манифеста приложения

    <queries>       ...         <intent>             <action                 android:name="android.settings.ACTION_PRINT_SETTINGS" />             <category                 android:name="android.intent.category.DEFAULT" />         </intent>       ...     </queries>

https://developer.android.com/guide/topics/manifest/queries-element

Начиная с апи 30 (11-й андроид) для секьюрности урезали доступ к списку установленных приложений и ресолвить доступные для выполнения намерения теперь можно только упомянув в манифесте.

По дефолту через startActivity запускается самая подходящая программа. Есть способ предложить пользователю выбрать из нескольких

PackageManager packageManager = requireActivity().getPackageManager(); Intent intent = new Intent(Settings.ACTION_PRINT_SETTINGS); // Create intent to show chooser Intent chooser = Intent.createChooser(intent, getString(R.string.open)); if (intent.resolveActivity(packageManager) != null) {     startActivity(chooser); }

Этот способ показывает выбор, но только, если пользователь в предыдущий раз не поставил [v] использовать всегда.

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

Хорошо, проверяем, что ресолвятся несколько компонентов

PackageManager packageManager = requireActivity().getPackageManager(); Intent intent = new Intent(Settings.ACTION_PRINT_SETTINGS);  List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(intent,                     PackageManager.GET_RESOLVED_FILTER);  if (resolveInfos.size() > 1) {    // ок их тут много }  

Уточнить нужный для запуска можно так

String packageName = resolveInfo.activityInfo.applicationInfo.packageName; intent.setPackage(packageName);

Время костылить

Из-за вот таких чудес производителей телефонов, да и просто из-за отличий в версиях андроида реальный код обрастает подпорками.

Делаю следующие предположения. Если для события больше одного обработчика, то производитель ввел его намеренно и нужно использовать его. На случай , если их три или больше, то буду брать первый отличный от штатного.

Окончательный код принимает такой вид.

PackageManager packageManager = requireActivity().getPackageManager(); Intent intent = new Intent(Settings.ACTION_PRINT_SETTINGS);  List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(intent,                     PackageManager.GET_RESOLVED_FILTER);   try {     if (resolveInfos.size() > 1) {        for (ResolveInfo resolveInfo : resolveInfos) {           if (resolveInfo.activityInfo != null) {                 String packageName = resolveInfo.activityInfo.applicationInfo.packageName;                  if (!"com.android.settings".equals(packageName)) {                       intent.setPackage(packageName);                        break;                  }           }        }    } } catch (Exception ignored) {}  try {    startActivity(intent); } catch (Exception e) {    Toast.makeText(requireActivity(), R.string.Oopppsss, Toast.LENGTH_SHORT).show(); }


ссылка на оригинал статьи https://habr.com/ru/articles/850270/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *