Development (Basic)

Step 1: Install Samsung DeX for PC and open an Android project for Code Lab

DeX for PC is a new way to use Samsung DeX on PC. Developers can share a PC monitor, keyboard, and mouse on DeX for PC. Developers can use either Win OS or Mac OS environment for their development.

  1. Run installer for DeX for PC to install.
  2. After completing the installation, connect your mobile device to your PC using a USB cable.
  3. Developers can now use IDE (Android Studio) for developing and Samsung DeX on PC together.
  4. Open provided Android project for CodeLab.

Base Project provided has the following features:

  • TextViews to show information
    • editText(R.id.edittxt): to input the Name
    • text1(R.id.txt1): to show the sentence with the name entered at editText
    • text2(R.id.txt2): to show the size of window
    • text3(R.id.txt3): to show the status if DeX is enabled or not. By default, it’s not visible. In Samsung DeX, it can show some text.
    • text4(R.id.txt4): to show how to change the size of the text via keyboard and mouse interaction
  • Buttons and switch to run other apps (for example, email) and subActivity

Step 2: Enabling mouse and keyboard interaction support

To run your app in Samsung DeX, there is a minimum requirement. If apps block fake touch input in DeX mode while allowing touch input, you may not use apps with a mouse or touchpad. So developers need to check whether codes for disabling mouse and keyboard interaction support are in the manifest or not.

Never declare the touchscreen support to disable the mouse and keyboard interactions.

<uses-configuration  android:reqTouchScreen="finger" />
<uses-feature  android:name="android.hardware.touchscreen"  android:required="true" />
    

Step 3: Enabling freeform (resizable) multi-window support

To run in Samsung DeX, apps should support Android Multi-Window – this enables minimizing, maximizing, and resizing. If Multi-Window is not supported, the app opens in a fixed-size window. For your app to have a PC-like experience, this needs to be considered.

  1. Apps should target SDK 24 or higher. Always check the targetSdkVersion is set to 24 or a higher at build.gradle file.

  2. Explicitly declare resizeableActivity to true in the Manifest to run in a Resizable Window.

    <activity
         …
        android:resizeableActivity="true">
    </activity>
    

    The app can now run in a freeform multi-window just as resizeableActivity is declared to True explicitly in manifest.

Step 4: Handle runtime configuration changes when resizing the window

Resizing the window causes runtime configuration changes similar to changing an orientation from portrait to landscape display. This may result in the application being forced to restart whenever resizing the window. The app shows a toast message whenever an app is created. Therefore, after resize, apps always show it and the sentence of text1 would be reset.

To ensure that this does not happen, add a configChanges flag to the activity in the manifest. You can get more information from Android's guide related to handling configuration changes as well as Android's best practices on building a responsive design.

  1. First, add android:configChanges flag to activity in Manifest. Here, all configChanges flags prevent the app from restarting in Samsung DeX.

    <application
        …
        <activity
        ...
        <!-- DeX TODO 
        The android:configChanges="colorMode|orientation|screenLayout|screenSize|smallestScreenSize|keyboardHidden|keyboard"this used 
        if you don't want android to kill and restart you activity when window is resized -->
        android:configChanges="colorMode|orientation|screenLayout|screenSize|smallestScreenSize|keyboardHidden|keyboard"
        >
               ...
               </activity>
    </application>
    
  2. Adding flags in manifest needs to be implemented because onConfigurationChanged callback method is called whenever configuration changes happen. Sample application already has the method, named updateWindowSize(), to check the size (width and height) of window and update the TextView (R.id.txt1) for showing the size of window.

    Here, it calls the updateWindowSize() whenever call onConfiguration Callback occurs.

    @Override
        public void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            updateWindowSize();
            }
    

    After this step, the app did not show the toast message after resizing the window and text1 was not set to default sentence.


Your app can check whether Samsung DeX is enabled or not in mobile device. It is one of the most useful features of Samsung DeX. If your device supports Samsung DeX and it is enabled, you can customize your app for DeX Mode. Your app can also check whether it is running in Samsung DeX or Phone mode. In this case, you can customize your app to work differently depending on the mode it is using.

Here, you can make your app show the status if it is enabled or not and can add a text to show which display mode the app is running in.

1. Check whether Samsung DeX is enabled or not

As you know, there is no SDK for Samsung DeX. Therefore, to check whether Samsung DeX is enabled or not, you need to use reflection method. Check and implement the following code inside the isDeXEnabled(). If Samsung DeX is enabled, it returns the value of true.

private boolean isDeXEnabled() {
    Object desktopModeManager = mContext.getApplicationContext().getSystemService("desktopmode");
        if (desktopModeManager != null) {
            try {
                Method getDesktopModeStateMethod = desktopModeManager.getClass().getDeclaredMethod("getDesktopModeState");
                Object desktopModeState = getDesktopModeStateMethod.invoke(desktopModeManager);
                Class desktopModeStateClass = desktopModeState.getClass();
                Method getEnabledMethod = desktopModeStateClass.getDeclaredMethod("getEnabled");
                int enabled = (int) getEnabledMethod.invoke(desktopModeState);
                boolean isEnabled = enabled == desktopModeStateClass.getDeclaredField("ENABLED").getInt(desktopModeStateClass);

                Method getDisplayTypeMethod = desktopModeStateClass.getDeclaredMethod("getDisplayType");
                int displayType = (int) getDisplayTypeMethod.invoke(desktopModeState);
                return isEnabled && displayType == desktopModeStateClass.getDeclaredField("DISPLAY_TYPE_DUAL").getInt(desktopModeStateClass);

            } catch (NoSuchFieldException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                // Device does not support DeX 3.0
                return false;
            }
        }
        return false;
    } 

2. Check which mode your app is currently running at

When checking which mode your app is running at, you also need to use reflection method. Check and implement the following code inside isAppCurrentlyRunningInDeX(). If your app is running at Samsung DeX mode, it returns the value of true.

private boolean isAppCurrentlyRunningInDeX() {
        Configuration config = mContext.getResources().getConfiguration();
        try {
            Class configClass = config.getClass();
            if (configClass.getField("SEM_DESKTOP_MODE_ENABLED").getInt(configClass) == configClass.getField("semDesktopModeEnabled").getInt(config)) {
                Toast.makeText(mContext, "isAppCurrentlyRunningInDeX: true", Toast.LENGTH_LONG).show();
                return true;
            }
        } catch (Exception ignored) {
        }
        return false;
}

3. Change the sentence accordingly to enable Samsung DeX mode

Using the return value from above methods, change the sentence for textView3.

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if(isDeXEnabled()){
            if(isAppCurrentlyRunningInDeX()){
                text3.setText("Samsung DeX Enabled \nNow, Your app is running in Samsung DeX");

            } else {
                text3.setText("Samsung DeX Enabled \nNow, Your app is running in Phone");
            }
        } else {
            text3.setText("Samsung DeX NOT Enabled");
        }
}

Step 6: Implementing keyboard features and combination keys (CTRL & mouse wheel)

If your app supports customized keyboard & mouse interactions aside from basic keyboard interactions, it can improve the user’s experience. In this step, you can try to add features to control the size for text4 with the combination of CTRL + Mouse-wheel.

  1. Add to check the status CTRL keys that has KeyEvent.KEYCODE_CTRL_LEFT and KeyEvent.KEYCODE_CTRL_RIGHT as a keyCode which would proceed to check its function when pressed and released.

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode) {
            case KeyEvent.KEYCODE_CTRL_LEFT:
            case KeyEvent.KEYCODE_CTRL_RIGHT:
                ctrlKeyPressed = true;
                break;
        }
        return super.onKeyDown(keyCode, event);
    }
    
    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        switch (keyCode) {
            case KeyEvent.KEYCODE_CTRL_LEFT:
            case KeyEvent.KEYCODE_CTRL_RIGHT:
                ctrlKeyPressed = false;
                break;
        }
        return super.onKeyUp(keyCode, event);
    } 
    

If you want to add more keyboard functionality, use the Android guide for Handling Keyboard Actions: https://developer.android.com/training/keyboard-input/commands.html

  1. Enable CTRL + Mouse-wheel combination to change the size of text.

    @Override
    protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
    
            text4.setOnGenericMotionListener(new View.OnGenericMotionListener() {
                @Override
                public boolean onGenericMotion(View view, MotionEvent motionEvent) {
                    int action = motionEvent.getAction();
                    if((action == MotionEvent.ACTION_SCROLL) && ctrlKeyPressed) {
                        float vScroll = motionEvent.getAxisValue(MotionEvent.AXIS_VSCROLL);
                        if(vScroll < 0){
                            //wheel down
                            text4.setTextSize(TypedValue.COMPLEX_UNIT_PX, text4.getTextSize()-1);
                        } else{
                            //wheel up
                            text4.setTextSize(TypedValue.COMPLEX_UNIT_PX, text4.getTextSize()+1);
                        }
    
                    }
                    return false;
                }
            });
    
    }