Open a New Desktop World on PC


Objective

Optimize your application and its input capabilities on Samsung DeX. In addition, implement some features using Samsung DeX Dual mode.

Overview

Since the launch of Galaxy S8 and S8+, Samsung Galaxy flagship devices have supported the Samsung DeX feature that extends the functionality of a mobile device into the desktop environment. In this Code Lab, you will learn how to optimize their Android apps for the next-gen Samsung devices with enhanced interaction, desktop mode capability, and a better app experience.

One of the advantages of Samsung DeX is that it does not require any SDKs to launch apps in Samsung DeX. However, apps must support mouse functionality and multi-density. For better UX in DeX mode, apps must adhere to a number of Android best practices, such as multi-window feature support. Desktop mode includes all the advanced multitasking features built in to the Samsung DeX UI. You can learn these through the tips and detailed instructions of this Code Lab.

Set up your environment

You will need the following:

  • Android Studio (latest version recommended)
  • Android SDK 24 or higher
  • Any Samsung Galaxy device that supports Samsung DeX for PC
  • USB-C to USB-A cable (if applicable)

Sample Code

Here is a sample code for you to start coding in this Code Lab. Download it and start your learning experience!

DeX Sample Code
(549.44 KB)

Install Samsung DeX for PC and open the project file

Samsung DeX for PC is the next feature of Samsung DeX, giving you an uninterrupted experience between your phone and your computer, which is available for both Windows OS. Here, you can share a PC monitor, keyboard, and mouse on DeX for PC.

  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. Open the downloaded sample code which contains the Android project for this Code Lab.

The 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

Enable 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. Here, you need to check whether the code for disabling mouse and keyboard interaction support are in the manifest or not.


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

Enable 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 file to run in a resizable window:

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

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

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 resizing, 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.

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 your phone or in DeX 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.

Check whether Samsung DeX is enabled or not

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;
    } 

Check which mode your app is currently running

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;
}

Change the prompt accordingly to enable Samsung DeX mode

Using the return value from above methods, change the sentence prompt 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");
        }
}

Implement keyboard features and combination keys

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);
    } 
    
    
  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;
                }
            });
    
    }
    
    

Run other apps on phone or DeX display in dual mode

Samsung DeX dual mode is a new feature of Samsung DeX starting with Galaxy Note9. With DeX for PC support, Samsung DeX dual mode has become more useful. For example, the app makes an activity or another app launches at a specific display. In this step, we implement to execute the email app at a specific display via button.

In the sample app, an email app can be launched on a specific monitor.

  1. Implement to run an email app via button1 (R.id.btn1).

    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            
            
            startEmail = (Button) findViewById(R.id.btn1);
            startEmail.setText("Start E-mail app");
            startEmail.setOnClickListener(this);
            
    }
    @Override
        public void onClick(View view) {
    
            switch (view.getId()){
                case R.id.btn1 :
                    Intent intent = getPackageManager().getLaunchIntentForPackage("com.google.android.gm");
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(intent);
    
                    break;
            }
        }   
    	
    
  2. Make it decide which display the app will run using a switch. The code snippet below can provide the information for target display.

    
    // Samsung DeX display
    DisplayManager dm = (DisplayManager)getSystemService(Context.DISPLAY_SERVICE);
    Display[] displays = dm.getDisplays("com.samsung.android.hardware.display.category.DESKTOP");
    Display targetDisplay = displays[0];
    
    // Phone display 
    DisplayManager dm = (DisplayManager)getSystemService(Context.DISPLAY_SERVICE);
    Display targetDisplay = dm.getDisplay(Display.DEFAULT_DISPLAY);
    
    

    The app needs to execute startActivity with the display information to get through ActivityOptions setLaunchDisplayId API. Finally, we need to change the code to run the email app.

    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            
            
            startEmail = (Button) findViewById(R.id.btn1);
            startEmail.setText("Start E-mail app");
            startEmail.setOnClickListener(this);
            
            sw = (Switch)findViewById(R.id.switch1);
            sw.setText("DeX display");
            
    }
    @Override
        public void onClick(View view) {
        Display targetDisplay;
            DisplayManager dm = (DisplayManager)getSystemService(Context.DISPLAY_SERVICE);
    
            if(sw.isChecked())
            {
                    Display[] displays = dm.getDisplays("com.samsung.android.hardware.display.category.DESKTOP");
                    targetDisplay = displays[0];
            }else {
                    targetDisplay = dm.getDisplay(Display.DEFAULT_DISPLAY);
            }
            switch (view.getId()){
                case R.id.btn1 :
                    Intent intent = getPackageManager().getLaunchIntentForPackage("com.google.android.gm");
                    if(isDeXEnabled()){
                        ActivityOptions options = ActivityOptions.makeBasic();
                        options.setLaunchDisplayId(targetDisplay.getDisplayId());
                        startActivity(intent, options.toBundle());
                    } else {
                        startActivity(intent);
                    }
                    break;
            }
        }
            
    

Utilize both phone and DeX display on dual mode

In Samsung DeX dual mode, your app can run different activities on both the phone display and DeX display.

In this case, you should consider a few things. First, you need to set target display like in previous step. Here, you used the targetDisplay defined previously. Second, to start an additional activity on multi-window, we need to add Intent.FLAG_ACTIVITY_NEW_TASK flag:


Intent intent2 = new Intent(MainActivity.this,SubActivity.class);
intent2.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        

Lastly, the meta-data should be added at manifest.


<application>
…
    <meta-data
    android:name="com.samsung.android.multidisplay.keep_process_alive"
    android:value="true" />
…
</application>

Samsung DeX (framework) does not allow a process to have tasks on multiple displays and contexts such as activities and services if they have the same displayId.

For this reason, only one instance of the app can run and the older instance of the app will be closed if a new instance is launched. However, some apps, including activity or service, needs multiple instances in certain situations. This meta-data keeps an application alive and capable of running multiple instances. An app developer has a responsibility to use proper context to make proper UIs, since the framework is not concerned about the process, application context, and package context.

In the sample app, SubActivity can run on a specific monitor. Next, implement to start SubActivity on the targetDisplay via button2(R.id.btn2):


protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
    
        startSubActivity = (Button) findViewById(R.id.btn2);
        startSubActivity.setText("Start \nSubActivity");
        startSubActivity.setOnClickListener(this);
    
}
case R.id.btn2 :
        Intent intent2 = new Intent(MainActivity.this,SubActivity.class);
        intent2.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

        if(isDeXEnabled()){
            ActivityOptions options = ActivityOptions.makeBasic();
            options.setLaunchDisplayId(targetDisplay.getDisplayId());
            startActivity(intent2, options.toBundle());
        } else {
            startActivity(intent2);
        }

        break;

Test dual mode

To open the email app and SubActivity in either DeX mode or in your phone, you may toggle the on DeX display button in the app.

When on DeX display button is turned off, the email app and activity will be launched in the phone.

Otherwise, it will be opened in DeX mode as seen below.

You're done!

Congratulations! You have successfully achieved the goal of this Code Lab. Now, you can optimize your app to be compatible with DeX environment by yourself! Keep in mind that you can modify your app to have a desktop-like experience without any restrictions or any SDK for Samsung DeX.

If you're having trouble, you may download this file:

DeX Complete Code
(8.60 MB)