Samsung DeX extends the functionality of a mobile device into a desktop environment. One of the advantages it offers is that it does not require any SDKs to launch apps on DeX Mode. However, the apps must support mouse functionality and multi-density.
For better user experience in DeX mode, apps must adhere to a number of Android best practices especially on multi-window feature support. DeX mode includes all of the advanced multitasking features built in the Samsung DeX UI.
In this Code Lab, you can learn how to optimize your apps for next-gen Samsung devices with enhanced interaction, desktop mode capability, and an overall amplified in-app experience. Moreover, you can experience the new dual mode which allows you to use DeX mode while using your phone simultaneously.
Optimize a sample application and its input capabilities with Samsung DeX.
Provide features using Samsung DeX Dual mode.
The following software and tools are needed to optimize apps for Samsung DeX:
Android Studio for PC or Android IDE for mobile with Android Developer Tools
Android SDK 24 or higher
Samsung Galaxy flagship device (S8, S8+, S9, S9+, Note8, Note9 and Tab S4) that supports Samsung DeX
External monitor
Samsung DeX Accessory: DeX Station, DeX Pad or HDMI adaptor
Keyboard and Mouse connected to the mobile device via Bluetooth (or hardwired to the DeX Station (Pad) via USB port)
A Sample/Pre-built application
1. Android Studio - https://developer.android.com/studio
2. Android SDK 24 or higher
You will be provided with a sample app that has the following features:
a) Simple drawing function
b) A floating button to open an e-mail app
c) 5 buttons for various features
Add window on the other display that works in DeX mode
Change the brush size
Undo
Redo
Erase all drawing
Figure 1 Sample App
In order for the app functionality to work in Samsung DeX, you need to check these requirements:
a) Apps must support Multi-Density for xxxhdpi (640 dpi) and mdpi (160 dpi).
b) Apps must support mouse or trackpad interaction.
These are important in DeX mode since it only supports mdpi as a density. If apps block fake touch input in DeX mode while allowing touch input, you may not use apps with a mouse or touchpad. It is a best practice to check these requirements even though most of the available apps now can run on Samsung DeX in fixed-sized multi-window without making any code changes to apps.
Figure 2 Items to be checked in manifest
By default, apps run in multi-window mode. However, multi-window mode has a fixed-size. If an app supports a freeform multi-window functionality, it would provide you a desktop experience where you can resize windows.
Follow these steps to enable support for freeform:
a) Apps should target at least SDK 24 or higher. Always check if the targetSdkVersion is set to 24 or higher at build.gradle file.
b) Explicitly declare resizeableActivity to True in the manifest to run in a resizable window. After declaring and enabling resizeableActivity, the sample app can now run in a resizable window mode.
<application
...
<activity
...
android:resizeableActivity="true"
>
...
</activity>
</application>
The switch between mobile phone and Samsung DeX mode causes runtime configuration changes, which happens similarly when changing the orientation from portrait to landscape display. This may result to force restart an application when switching between modes.
You need to follow the Android's guide for handling configuration changes and the best practices on building a responsive design to avoid any runtime configuration issues.
a) To modify, add android:configChanges flag to activity in Manifest
<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>
In the manifest file, you can set the minimum window size and launch size of DeX mode. Moreover, you can set the app to be always active when switching from phone to DeX mode or vice versa to avoid restarting the app.
a) To set the minimum window size when in DeX mode, follow the code snippet below.
<application
...
<activity
...
<!--Layout minimum size set in DeX mode -->
<layout android:minWidth="320dp" android:minHeight="700dp"/>
<!--Layout minimum size set in DeX mode -->
...
</activity>
</application>
b) Enable the ‘keep alive’ setting in the manifest file to avoid making the app restart when switching from phone to DeX mode or vice versa.
<application
…
<!--Keep alive settings -->
<meta-data
android:name="com.samsung.android.keepalive.density"
android:value="true" />
<meta-data
android:name="com.samsung.android.multidisplay.keep_process_alive"
android:value="true" />
<!--Keep alive settings -->
…
</application>
c) Change the launch size of the app through the following:
<application
…
<!-- app launch size set in DeX mode -->
<meta-data
android:name="com.samsung.android.dex.launchwidth"
android:value="1024"/>
<meta-data
android:name="com.samsung.android.dex.launchheight"
android:value="800"/>
<!-- app launch size set in DeX mode-->
…
</application>
In this step, you will prevent the app from restarting whenever resizing the window. In addition, the handling of the runtime configuration can be changed through
onConfigurationChanged(). Moreover, the updated information will be displayed after resizing the window in DeX mode.
a) Add the function below to check whether the current mode is on Samsung DeX or not.
public class DeXUtils {
…
…
@SuppressWarnings("unchecked")
static boolean isDeXAvailable(Context context) {
@SuppressLint("WrongConstant")
Object desktopModeManager = context.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);
boolean isDualMode = isEnabled && displayType == desktopModeStateClass.getDeclaredField("DISPLAY_TYPE_DUAL").getInt(desktopModeStateClass);
boolean isStandaloneMode = isEnabled && displayType == desktopModeStateClass.getDeclaredField("DISPLAY_TYPE_STANDALONE").getInt(desktopModeStateClass);
// Check isEnabled, isDualMode or isStandaloneMode as you want
String msg = "DeX: isEnabled=" + isEnabled + ", isDualMode=" + isDualMode + ", isStandaloneMode=" + isStandaloneMode + ", isAppCurrentlyRunningInDeX=" + isAppCurrentlyRunningInDeX(context);
Log.d(TAG, msg);
//Toast.makeText(context, msg, Toast.LENGTH_LONG).show();
return isEnabled | isDualMode | isStandaloneMode | isAppCurrentlyRunningInDeX(context);
} catch (NoSuchFieldException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
// Device does not support DeX 3.0
return false;
}
} else {
// Device does not support Samsung DeX or called too early on boot
return false;
}
}
…
…
}
b) Implement onConfigurationChanged() and other functions to show updated information for density, orientation, width of window, height of window, and UI mode after resizing the window.
public class MainActivity extends AppCompatActivity {
…
…
//isSamsungDex : onConfigurationChanged
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Log.d(TAG,"onConfigurationChanged");
if (DeXUtils.isDeXAvailable(getApplication())) {
hiddenLayout.setVisibility(View.VISIBLE);
showTheValueChanged();
} else {
hiddenLayout.setVisibility(View.GONE);
}
}
//Samsung DeX: Hidden Layout Needs below functions
@SuppressLint("SetTextI18n")
private void showTheValueChanged() {
TextView valueText = findViewById(R.id.values);
valueText.setText("Density : " + getDensity()
+ " | Orientation : " + getOrientation()
+ " | (width, height) : (" + Integer.toString(getResources().getConfiguration().screenWidthDp) + ", " + Integer.toString(getResources().getConfiguration().screenHeightDp) + ")"
+ " | UI Mode : " + getUImode());
}
private String getUImode()
{
int screenUimode = getResources().getConfiguration().uiMode & Configuration.UI_MODE_TYPE_MASK;
switch(screenUimode){
case Configuration.UI_MODE_TYPE_DESK :
return "DESK MODE";
case Configuration.UI_MODE_TYPE_NORMAL :
return "NORMAL MODE";
default :
return null;
}
}
private String getOrientation()
{
int orientation = getResources().getConfiguration().orientation;
if(Configuration.ORIENTATION_LANDSCAPE == orientation){
return "Landscape";
} else if(Configuration.ORIENTATION_PORTRAIT == orientation){
return "Portrait";
}
return null;
}
private String getDensity()
{
float density = getResources().getDisplayMetrics().density;
if(density >= 4.0){
return "xxxhdpi";
} else if(density >= 3.0){
return "xxhdpi";
} else if(density >= 2.0){
return "xhdpi";
} else if(density >= 1.5){
return "hdpi";
} else if(density >= 1.0){
return "mdpi";
} else {
return "ldpi";
}
}
…
…
}
c) When the app detects DeX mode, it will be shown at the top side of the layout as implemented below.
public class MainActivity extends AppCompatActivity {
…
…
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
…
…
//isSamsungDex : Hidden Layout
//Checking the Samsung DeX and then you have to set up hiddenlayout
hiddenLayout = findViewById(R.id.hidden);
if (DeXUtils.isDeXAvailable(getApplication())) {
CheckPermission();
hiddenLayout.setVisibility(View.VISIBLE);
showTheValueChanged();
}
…
…
}
}
d) To make the dual mode button show a window on the external monitor, use the following:
public class MainActivity extends AppCompatActivity {
…
…
//isSamsungDex : Share Button
private void handleDrawingIconTouched(int itemId) {
switch (itemId) {
case R.id.action_delete:
deleteDialog();
break;
case R.id.action_undo:
mCustomView.onClickUndo();
break;
case R.id.action_redo:
mCustomView.onClickRedo();
break;
case R.id.action_brush:
brushSizePicker();
break;
case R.id.action_share:
if (DeXUtils.isDeXAvailable(getApplication())) {
AddWindowAfterCheckPermission();
} else {
Toast.makeText(getApplicationContext(), "This function will only work if Samsung's DeX mode is available.", Toast.LENGTH_LONG).show();
}
break;
}
}
…
…
}
The keyboard interaction with Samsung DeX supports the following functions:
Closing popups, Esc
Switch between open apps , Alt+Tab
Take screenshot, Print Screen
Keyboard shortcuts:
Undo, Ctrl-Z
Redo, Ctrl-Y
Cut, Ctrl-X
Copy, Ctrl-C
Paste, Ctrl-V
Select all, Ctrl-A
To add more keyboard functionalities to your app in DeX mode, use onKeyDown(), onKeyUp(), and the value of keyCode which is the Key Event code. In the sample app, add the feature to increase or decrease the brush size using the combination of the CTRL key and the mouse wheel.
a) First, you add the CTRL keys using the code snippet below. The function added below checks when the key has been pressed or released.
public class MainActivity extends AppCompatActivity {
…
…
//Keyboard input functions
//On key press
@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);
}
//On key release
@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.onKeyDown(keyCode, event);
}
//Key function
…
…
}
For more information on adding keyboard functionality, use the Android guide for handling keyboard event actions, in the following link: https://developer.android.com/training/keyboard-input/commands.html
b) Enable the CTRL + Mouse-wheel combination to change brush size.
public class MainActivity extends AppCompatActivity {
…
…
protected void onCreate(Bundle savedInstanceState) {
…
…
//Ctl key + mouse wheel : change the brush size
mCustomView.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
if (brushSizewithWheel > getResources().getInteger(R.integer.min_size))
brushSizewithWheel--;
else
brushSizewithWheel = getResources().getInteger(R.integer.min_size);
} else {
//wheel up
if (brushSizewithWheel < getResources().getInteger(R.integer.max_size))
brushSizewithWheel++;
else
brushSizewithWheel = getResources().getInteger(R.integer.max_size);
}
Toast.makeText(getApplicationContext(), "Brush Size : " + brushSizewithWheel, Toast.LENGTH_LONG).show();
mCustomView.setBrushSize(brushSizewithWheel);
mCustomView.setLastBrushSize(brushSizewithWheel);
}
return true;
}
});
//Ctl key + mouse wheel : change the brush size
…
}
…
…
}
c) Add the redo and undo function with combination of the CTRL and ‘Z’ or ‘Y’ keys.
public class MainActivity extends AppCompatActivity {
…
…
//Key function
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_Y:
if (ctrlkeyPressed)
mCustomView.onClickRedo();
break;
case KeyEvent.KEYCODE_Z:
if (ctrlkeyPressed)
mCustomView.onClickUndo();
break;
}
return super.onKeyDown(keyCode, event);
}
//Key function
…
…
}
Using the right-click button on the app will show the context menu. This menu provides additional options for easier access to the dual mode, brush size, undo, and redo. Enable this on the right-click of the mouse by using the onTouchEvent() and MotionEvent.BUTTON_SECONDARY. In the sample app, you can add the context menu on the CustomView.
a) Initially, you have to register the context menu in the CustomView.
public class MainActivity extends AppCompatActivity {
…
…
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
…
…
//Mouse Right Click
//Register context menu for mouse right click
mCustomView = findViewById(R.id.custom_view);
registerForContextMenu(mCustomView);
…
…
}
…
…
}
b) Using the code below, implement the context menu on the right-click of the mouse.
public class MainActivity extends AppCompatActivity {
…
…
//Mouse Right Click : When mouse right click, context menu will appear.
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
Log.d(TAG, "onCreate Context menu :" + v.getId() + " : " + R.id.custom_view);
if (v.getId() == R.id.custom_view) {
menu.setHeaderTitle("Drawing Option");
getMenuInflater().inflate(R.menu.menu_drawing, menu);
}
super.onCreateContextMenu(menu, v, menuInfo);
}
@Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_delete:
deleteDialog();
break;
case R.id.action_undo:
mCustomView.onClickUndo();
break;
case R.id.action_redo:
mCustomView.onClickRedo();
break;
case R.id.action_brush:
brushSizePicker();
break;
case R.id.action_share:
if (DeXUtils.isDeXAvailable(getApplication()))
AddWindowAfterCheckPermission();
else
Toast.makeText(getApplicationContext(), "This function will only work if it is connected to an external monitor.", Toast.LENGTH_LONG).show();
break;
default:
return super.onContextItemSelected(item);
}
return super.onContextItemSelected(item);
}
//Mouse right click
…
…
}
Dual mode is a new feature of Samsung DeX where you can set up DeX mode on the monitor while allowing you to use different apps on your phone simultaneously.
In this step, you can experience dual mode. That is, the e-mail app can run and be displayed on the external monitor while allowing you to use the phone independently from the DeX mode.
a) If you click the e-mail app button, it should launch the app on the external display that is on DeX mode.
public class MainActivity extends AppCompatActivity {
…
…
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
…
…
FloatingActionButton fab = findViewById(R.id.email_fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Display currentDisplay = getWindow().getDecorView().getDisplay();
ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchDisplayId(DeXUtils.getOtherDisplayId(getApplication(), currentDisplay));
Intent intent = getPackageManager().getLaunchIntentForPackage("com.google.android.gm");
assert intent != null;
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent, options.toBundle());
}
});
…
…
}
…
…
}
b) To add window on the external monitor, click the dual view button on the app.
public class MainActivity extends AppCompatActivity {
…
…
//isSamsungDex : Share Button
private void handleDrawingIconTouched(int itemId) {
switch (itemId){
…
case R.id.action_share:
if (DeXUtils.isDeXAvailable(getApplication())) {
AddWindowAfterCheckPermission();
} else {
Toast.makeText(getApplicationContext(), "This function will only work if Samsung's DeX mode is available.", Toast.LENGTH_LONG).show();
}
break;
}
}
@Override
public boolean onContextItemSelected(MenuItem item){
switch (item.getItemId()){
…
case R.id.action_share:
if (DeXUtils.isDeXAvailable(getApplication()))
AddWindowAfterCheckPermission();
else
Toast.makeText(getApplicationContext(), "This function will only work if it is connected to an external monitor.", Toast.LENGTH_LONG).show();
break;
default:
return super.onContextItemSelected(item);
}
return super.onContextItemSelected(item);
}
//Mouse right click
//Add Windown on external mointor
void addWindowInSecondaryDisplay() {
if (mViewInSencondaryDisplay == null) {
Display currentDisplay = getWindow().getDecorView().getDisplay();
//Get the Secondary window manager
Context displayContext = mContext.createDisplayContext(DeXUtils.getOtherDisplay(getApplication(), getWindowManager(), currentDisplay));
mSecondaryWm = (WindowManager) displayContext.getSystemService(Context.WINDOW_SERVICE);
//Get the Layout for secondary window
LayoutInflater li = (LayoutInflater) displayContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
LinearLayout layout = new LinearLayout(displayContext);
mViewInSencondaryDisplay = Objects.requireNonNull(li).inflate(R.layout.activity_dualview, layout, false);
//Setting the window layout
WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.width = WindowManager.LayoutParams.MATCH_PARENT;
params.height = WindowManager.LayoutParams.MATCH_PARENT;
params.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR;
params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
mViewInSencondaryDisplay.setBackgroundColor(Color.WHITE);
//Immersive mode setting : Full Screen
DeXUtils.immersiveMode(mViewInSencondaryDisplay);
mViewInSencondaryDisplay.setOnSystemUiVisibilityChangeListener(
new View.OnSystemUiVisibilityChangeListener() {
@Override
public void onSystemUiVisibilityChange(int visibility) {
if (mViewInSencondaryDisplay != null) {
DeXUtils.immersiveMode(mViewInSencondaryDisplay);
}
}
});
getWindow().setNavigationBarColor(Color.WHITE);
imgbtn_window_close = (ImageView) mViewInSencondaryDisplay.findViewById(R.id.dualView_Image);
imgbtn_window_close.setOnClickListener(mBtnClickLisner);
//Add window display configurations to window manager
mSecondaryWm.addView(mViewInSencondaryDisplay, params);
Log.d(TAG, "Secondary Window Added");
//Toast.makeText(getApplicationContext(),"Secondary Window Added",Toast.LENGTH_LONG).show();
}
}
//When click the image button, Secondary window will be closed.
View.OnClickListener mBtnClickLisner = new View.OnClickListener(){
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.dualView_Image:
removeWindowInSecondaryDisplay();
break;
default:
break;
}
}
};
void removeWindowInSecondaryDisplay() {
if(mViewInSencondaryDisplay != null) {
mSecondaryWm.removeView(mViewInSencondaryDisplay);
mViewInSencondaryDisplay = null;
mSecondaryWm = null;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy" );
removeWindowInSecondaryDisplay();
}
//Add Windown on external mointor
…
…
}
public class DeXUtils {
…
…
static int getOtherDisplayId(Context context, Display currentDisplay){
DisplayManager dm = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
Display[] displays = Objects.requireNonNull(dm).getDisplays("com.samsung.android.hardware.display.category.DESKTOP");
int targetDisplayId;
if(currentDisplay.getDisplayId() == Display.DEFAULT_DISPLAY){
targetDisplayId = displays[0].getDisplayId();
}else {
targetDisplayId = Display.DEFAULT_DISPLAY;
}
return targetDisplayId;
}
static Display getOtherDisplay(Context context, WindowManager wm, Display currentDisplay){
Display targetDisplay;
//Get the target Display.
if(currentDisplay.getDisplayId() == Display.DEFAULT_DISPLAY) {
targetDisplay = getExternalDisplay(context, wm);
} else {
DisplayManager dm = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
targetDisplay = Objects.requireNonNull(dm).getDisplay(Display.DEFAULT_DISPLAY);
}
return targetDisplay;
}
private static Display getExternalDisplay(Context context, WindowManager wm) {
DisplayManager dm = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
Display[] displays = Objects.requireNonNull(dm).getDisplays("com.samsung.android.hardware.display.category.DESKTOP");
if(displays.length == 0) {
displays = dm.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION);
}
int count = displays.length;
Log.d(TAG, "count " + count);
for(int i = 0; i < count; i++) {
Log.d(TAG, "Display " + i + " " + displays[i]);
}
if(displays.length > 0) {
return displays[0];
}
return wm.getDefaultDisplay();
}
static void immersiveMode(View mViewInSencondaryDisplay){
//Immersive mode setting : Full Screen
final int flags = View.SYSTEM_UI_FLAG_LOW_PROFILE
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
// Set the content to appear under the system bars so that the
// content doesn't resize when the system bars hide and show.
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
// Hide the nav bar and status bar
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
mViewInSencondaryDisplay.setSystemUiVisibility( flags );
}
…
…
}
c) You have to enable overlay permission in the device settings whenever adding window on the display. Follow the sample code below to enable and directly call ‘overlay permission dialog’.
public class MainActivity extends AppCompatActivity {
…
…
@SuppressWarnings("StatementWithEmptyBody")
@TargetApi(Build.VERSION_CODES.M)
@Override
//Overay permission check
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE) {
if (!Settings.canDrawOverlays(this)) {
AddWindowAfterCheckPermission();
} else {
// Do as per your logic
}
}
}
//Overay permission
@SuppressLint("ObsoleteSdkInt")
private void AddWindowAfterCheckPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE);
} else {
// Add window
if (mViewInSencondaryDisplay == null) {
addWindowInSecondaryDisplay();
} else {
removeWindowInSecondaryDisplay();
}
}
}
}
//Add Windown on external mointor
…
…
}
By doing these steps, you have optimized your app to work with Samsung DeX. Adding other features is available on Samsung DeX. You can modify your app without any restrictions by making your app have a desktop-like experience.