Lukáš Benke
Lukáš Benke

Reputation: 371

Samsung devices does not close app drawer after CLOSE_SYSTEM_DIALOGS broadcast

I'm developing a simple Kiosk Mode application for Android 6.0. I have everything working on devices from Xiaomi, HTC, Lenovo, etc. but I can't get one feature working on any Samsung device.

The feature is automatic closing of every system system dialog using

Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
sendBroadcast(closeDialog);

This is broadcasted from a Service.

On my other, non-samsung devices, everything works and all system dialogs closes, but on any Samsung device (S5, S6 edge, ...) this broadcast gets ignored and for example the app drawer stays opened.

I've observed that even using ADB to broadcast this intent, app drawer stays opened, but for example the shutdown device dialog gets closed if I broadcast this from adb.

Please note that this is not malicious action in context of this software, this is for client, that requires this feature and it is completely solicited.

I've done research on Samsung Knox, but we would have to obtain their license for using the Knox Standard SDK and that is not something that is in the scope of this project.

So my question is: Do you have any idea how to make this work (closing the app drawer with ACTION_CLOSE_SYSTEM_DIALOGS intent) on samsung devices with Knox installed?

Thanks.

Upvotes: 11

Views: 1312

Answers (2)

ChRoNoN
ChRoNoN

Reputation: 900

The problem with the most commonly found solution is that dialogs are totally different window, so you need to override the onWindowsFocusChanged on them as well. That can lead to a lot of work, plus the menu also open the same flaw to call the power menu.

The best solution I found is to implement a service to close the system dialogs when a long press of the power key is detected. I tested on couple of LG devices (Android 5.1.1 and 6.0) and calling this from a service was working just fine:

sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));

But on Samsung tablets (Android 5.1.1) it did not work, after trying few different solutions with no luck. I finally got it working when send an intent to an activity and make the activity send the broadcast:

Add this to your manifest:

<service 
        android:name="com.mypackage.services.PowerButtonService"
        android:enabled="true"
        android:exported="true"
        android:permission="android.permission.SYSTEM_ALERT_WINDOW"
        android:stopWithTask="true"/>

<activity
    android:name="com.mypackage.activities.CloseSystemDialogActivity"
    android:launchMode="singleTask">

    <intent-filter>
        <action android:name="CloseSystemDialogActivity.ACTION_CLOSE_DIALOGS"/>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</activity>

The service:

public class PowerButtonService extends Service {
    private View view;
    private WindowManager windowManager;

    @Override
    public void onCreate() {
        super.onCreate();

        LinearLayout linearLayout = new LinearLayout(getApplicationContext()) {
            @SuppressWarnings("unused")
            public void onCloseSystemDialogs(String reason) {
                if ("globalactions".equals(reason)) {
                    final Intent intent = new Intent(CloseSystemDialogActivity.ACTION_CLOSE_DIALOGS);
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(intent);
                }
            }
        };

        linearLayout.setFocusable(true);

        WindowManager.LayoutParams params = new WindowManager.LayoutParams(100, 100, WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
                                                                           WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_FULLSCREEN
                                                                           | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                                                                           | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT);
        params.gravity = Gravity.START | Gravity.CENTER_VERTICAL;

        view = LayoutInflater.from(this).inflate(R.layout.empty, linearLayout);
        windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
        windowManager.addView(view, params);
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // VERY IMPORTANT
        windowManager.removeView(view);
    }

    @Override
    public int onStartCommand(final Intent intent, final int flags, final int startId) {
        return START_STICKY;
    }
}

Dummy activity:

public class CloseSystemDialogActivity extends Activity {
    public static final String ACTION_CLOSE_DIALOGS = "CloseSystemDialogActivity.ACTION_CLOSE_DIALOGS";

    @Override
    protected void onCreate(@Nullable final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
        finish();
    }
}

Notice that you NEED to START and STOP the service otherwise when your application is not running (out of kiosk mode) you might not be able to call the power menu if you need to.

Upvotes: 0

Haris ali
Haris ali

Reputation: 783

Try doing it like this :

 @Override
public void onWindowFocusChanged(boolean focus) {
        super.onWindowFocusChanged(focus);

        if (! focus) {
            Intent close= new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
            sendBroadcast(close);
        }
    }

Upvotes: 3

Related Questions