Год назад появился смартфон Samsung Galaxy S8/S8+, а вместе с ним и док-станция DeX, позволяющая пользователю превратить телефон в полноценный компьютер. Для этого достаточно поставить телефон на станцию, и на экране подключенного монитора отобразится рабочий стол, похожий на Windows 8+, а также будут доступны другие периферийные устройства (мышь, клавиатура, принтер). Инновационная архитектура приложения МойОфис Документы позволяет адаптировать и поддержать технологические новинки (такие как DeX) без существенных затрат. Особенно приятно, что стоимость внедрения такого решения невелика, а количество пользователей, которые могут задействовать приложения на большом экране, достаточно высоко. В этой статье мы поделимся с вами опытом, как реализовать поддержку док-станции DeX в вашем Android-приложении.


image


Особенности оптимизации функциональности приложений для работы с Samsung DeX


Прежде чем мы углубимся в технические особенности, стоит отметить, что многое из описанного ниже можно использовать не только в связке с Samsung DeX, достаточно подключить любую Bluetooth-клавиатуру и/или Bluetooth-мышь. Очевидно, что для удобства использования вашего приложения с подключенной периферией необходимо будет произвести ряд манипуляций с самим приложением. И хотя далеко не каждому приложению нужна поддержка десктопного режима, гибкость в использовании никогда не бывает лишней.


image
Источник: Samsung


Итак, поехали! Прежде всего следует кратко рассмотреть, что именно нужно изменить в приложении, чтобы оно хорошо смотрелось на Samsung DeX и с ним было комфортно работать пользователю.


Начнем с того, что Samsung DeX — это по сути доработка многооконного режима, появившегося в Android 7 (Nougat). То есть если ваше приложение уже приспособлено к работе в этом режиме, то никаких проблем при запуске на док-станции не будет. Однако для полноценного мимикрирования под десктоп необходимо учесть ряд особенностей и добавить дополнительную функциональность, представленную в таблице ниже и условно разделенную на основную и предпочтительную:



Запускаемые на Samsung DeX приложения условно можно разделить на три группы в зависимости от типа окна:


  1. Окно с изменяемым размером. То есть приложение полностью поддерживает все стандарты многооконного режима в Android N.
  2. Окно с фиксированным размером. То есть не все «фишечки» Android N учтены при разработке.
  3. Нет поддержки многооконности. Ну, значит, и не надо. На Samsung DeX такие приложения, очевидно, работать не будут.

На деле все будет выглядеть следующим образом:



МойОфис Документы


Теперь же углубимся в детали.


Поддержка разной плотности пикселей экрана


Как уже было отмечено выше, ваши приложения, запущенные непосредственно на мобильном телефоне (речь идет о Samsung Galaxy S8/S8+) и транслируемые посредством док-станции, будут иметь разные значения dpi: 640 dpi (xxhdpi) и 160 dpi (mdpi) соответственно. Так что если вы еще не используете векторную графику, то стоит подготовить соответствующие ресурсы для изображений. Также нужно учесть, что может поплыть верстка, — следует подготовить альтернативные лэйауты как один из вариантов решения проблемы. Более подробно о работе с экранами с различной плотностью пикселей можно почитать в официальной документации для разработчиков Android.


Поддержка изменяемости размеров окна и многооконности


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


android: resizableActivity = "true"

Поддержка многооконности — «фишка» не новая, наверняка с выходом Android Nougat многие успели ее прикрутить или хотя бы посмотреть в ее сторону. Все неплохо расписано в официальной документации. Реализовать данную функциональность достаточно просто: ставим флажок в манифесте, и готово:


<application
    android:resizeableActivity="true">
</application>

Тут стоит учесть, что при переходе в многооконный режим и наоборот activity будет пересоздаваться каждый раз, так как в этом случае система должна выбрать необходимые ресурсы. В условиях нашего приложения МойОфис Документы activity пересоздаваться нельзя, поэтому мы используем следующий набор флагов в манифесте в «непересоздаваемых» activity:


android:configChanges="orientation|keyboardHidden|screenSize|uiMode|screenLayout|smallestScreenSize"

В этом случае все необходимые замены лэйаутов необходимо обрабатывать ручками, например в методе onConfigurationChanged(Configuration newConfig) activity.


Жизнь приложения при выходе из desktop-режима


Нам может потребоваться узнать, находимся ли мы сейчас в desktop-режиме посредством DeX-станции (как правило, для изменения UI приложения). Делается это следующим образом:


public boolean isDexMode(@NonNull Context context) {
        Configuration config = context.getResources().getConfiguration();
        try {
            Class configClass = config.getClass();
            return configClass.getField("SEM_DESKTOP_MODE_ENABLED").getInt(configClass) ==
                    configClass.getField("semDesktopModeEnabled").getInt(config);
        } catch (NoSuchFieldException | IllegalAccessException | IllegalArgumentException e) {
            // ошибочка вышла
        }
        return false;
    }

А следующий флаг в манифесте необходим для установки поведения приложения при выходе из desktop-режима:


<meta-data android:name="com.samsung.android.keepalive.density" android:value="true"/>

В приведенной ниже таблице показано, как будет вести себя приложение при установленном флаге или без него:



 


Скроллирование


Прокрутка контента в десктопном режиме осуществляется колесиком мыши, а сам принцип скроллинга работает автоматически при использовании ListView, RecyclerView, GridView или ScrollView/HorizontalScrollView компонентов. Дополнительно рекомендуется реализовать поддержку полос прокрутки, чтобы пользователь мог совершить прокрутку, потянув за соответствующий компонент. Также можно добавить скроллирование посредством колесика мыши, если вы реализуете свой компонент, как это сделано в нашем случае, но об этом будет написано немного ниже (а добавление полос прокрутки осуществляется достаточно просто).


Работа с мышью и клавиатурой


Поддержка мыши может быть полезна для множества приложений (карты и навигация; игры; в нашем случае документы и т. п.), которые запускаются на DeX док-станции.


У объекта MotionEvent есть метод getSource(), при помощи которого можно определить источник данного события. В коде это выглядит так:


@Override
    public boolean onTouchEvent(MotionEvent event) {
        boolean isMouse = InputDevice.SOURCE_MOUSE == event.getSource();
        ...
    }

Понять, что по элементу произошел тач правой кнопкой мыши, можно при помощи метода getButtonState() у объекта MotionEvent:


boolean isRightClick = isMouse && buttonState == MotionEvent.BUTTON_SECONDARY;

Теперь по клику правой кнопкой мыши можно открыть контекстное меню.


Однако в ряде моделей телефонов (не Sumsung Galaxy S8/S8+) реализована иная логика обработки нажатия на правую кнопку мыши. Поэтому на этих устройствах реализация этих функций будет недоступна.


Работа с мышью не была бы полноценной, если бы при помощи ее колесика нельзя было скроллить и зумить. Следующий участок кода демонстрирует работу с колесиком мыши:


    @Override
    public boolean onGenericMotionEvent(MotionEvent event) {
        boolean isMouse = event.getSource() == InputDevice.SOURCE_MOUSE;
        if (isMouse) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_SCROLL:
                    float axisValue = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
                    if (event.isCtrlPressed()) {
// при зажатом Ctrl у нас происходит зум
                        zoomByMouse(axisValue);
                    } else if (event.isShiftPressed()) {
// при зажатом шифте скроллирование по оси X
                        scrollX(axisValue);
                    } else {
// скроллирование по оси Y
                        scrollY(axisValue);
                    }
                    break;
            }
            return true;
        }
        return false;
    }

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


Изменение курсора


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


android:state_hovered="true"

Далее нужно непосредственно в коде установить для вью кастомный PointerIcon при помощи метода setPointerIcon() (см. также view.onResolvePointerIcon(...)).


Поддержка хардварной клавиатуры производится проще: достаточно ее просто подключить к устройству. Единственное, на что стоит обратить внимание, — это обработка хоткеев:


    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (event.isCtrlPressed()) {
            switch (event.getKeyCode()) {
                case KeyEvent.KEYCODE_C:
                    // копируем
                    return true;
                case KeyEvent.KEYCODE_V:
                    // вставляем
                    return true;
            }
        }
        return super.onKeyDown(keyCode, event);
    }

Дополнительно


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


  • Drag&Drop файлов позволяет переносить файлики между вьюшками.
  • Click & Drag выделенного текста является как бы продолжением предыдущего пункта: можно выделить текст в одном приложении и перетащить его в наше приложение. Это очень удобно, так как даже не нужно нажимать шорткаты Ctrl-C/Ctrl-V. В приложении МойОфис Документы таким образом можно перетаскивать текст из одного документа в другой.

Ниже приведен пример имплементации OnDragListener:


// сетим реализацию интерфейса любой вьюшки (работает только для Android N и выше)
view.setOnDragListener(new OnDragListener(this))

  public class OnDragListener implements View.OnDragListener {

        @NonNull
        private AppCompatActivity activity;

        public OnDragListener(@NonNull AppCompatActivity activity) {
            this.activity = activity;
        }

        @Override
        @TargetApi(Build.VERSION_CODES.N)
        public boolean onDrag(View view, DragEvent dragEvent) {
            switch (dragEvent.getAction()) {
                case DragEvent.ACTION_DRAG_ENTERED:
                    return false;
                case DragEvent.ACTION_DRAG_EXITED:
                    return true;
                case DragEvent.ACTION_DRAG_STARTED:
                    return true;
                case DragEvent.ACTION_DROP: {
                    DragAndDropPermissions dragAndDropPermissions = activity.requestDragAndDropPermissions(dragEvent);
                    if (dragAndDropPermissions != null) {
                        ClipboardUtils clipboardUtils = ClipboardUtils.getInstance(activity);
                        String droppedPlainText = clipboardUtils.getClipboardPlainText(dragEvent.getClipData());
                        if (clipboardUtils.isRichTextInClipboard(droppedPlainText)) {
                            // insert rich text
                        } else {
                            // insert plain text
                        }
                    }
                    break;
                }
                default:
            }
            return true;
        }
    }


Тестирование


Как все это тестировать? Самый простой способ — это приобрести док-станцию Samsung DeX, подключить к ней всю периферию и баловаться. Если док-станции по каким-либо причинам в наличии нет, то, как уже было отмечено выше, можно просто подключить к смартфону, а еще лучше планшету, желательно, с Android 7 и выше, Bluetooth-клавиатуру и мышь. Также можно воспользоваться способом, предлагаемым непосредственно Samsung, если вы предпочитаете работать с эмулятором.


Заключение


Определенно, как железка, Samsung DeX — устройство интересное и точно будет востребовано у тех пользователей, которым важны мобильность и необходимость заменить несколько рабочих девайсов смартфоном. В соответствии с нашим опытом практически любое приложение можно с легкостью адаптировать для работы в десктопном режиме на этой док-станции или при присоединении хардварных контроллов. Надеемся, что эта статья будет вам полезна.

Комментарии (3)


  1. lieff
    19.04.2018 15:30

    А Linux на DeX уже кто-нибудь пробовал?


  1. gt8one
    20.04.2018 05:51

    А иконки в панели задач будут как на скриншоте, одинаковые для всех типов документов (Текст, Таблицы, Презентации)?


    1. myoffice_ru Автор
      20.04.2018 14:26

      В нашем приложении для каждого нового экрана иконка выставляется программно через TaskDescription. Однако, в десктопном режиме сама иконка на панели задач будет изменена только если отключить, а потом включить DeX режим. Если этого не сделать, иконка будет соответствовать родительскому окну.

      В других случаях иконка всегда соответствует иконке родительского окна, для нас чаще всего это file manager МойОфис Документы.