17805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani/*
27805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani * Copyright (C) 2014 The Android Open Source Project
37805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani *
47805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani * Licensed under the Apache License, Version 2.0 (the "License");
57805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani * you may not use this file except in compliance with the License.
67805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani * You may obtain a copy of the License at
77805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani *
87805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani *      http://www.apache.org/licenses/LICENSE-2.0
97805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani *
107805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani * Unless required by applicable law or agreed to in writing, software
117805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani * distributed under the License is distributed on an "AS IS" BASIS,
127805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani * See the License for the specific language governing permissions and
147805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani * limitations under the License.
157805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani */
167805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani
177805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasanipackage com.android.server.am;
187805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani
19c2a8d151dcd8e04dd67e5adbdf68b9795932ad82Amith Yamasaniimport android.app.AlertDialog;
207805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasaniimport android.content.Context;
217805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasaniimport android.content.res.Resources;
225e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasaniimport android.os.Handler;
235e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasaniimport android.os.Message;
24c2a8d151dcd8e04dd67e5adbdf68b9795932ad82Amith Yamasaniimport android.view.LayoutInflater;
25c2a8d151dcd8e04dd67e5adbdf68b9795932ad82Amith Yamasaniimport android.view.View;
269c79504225f60c72c947220b6aca928f11279e1cCraig Mautnerimport android.view.ViewTreeObserver;
277805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasaniimport android.view.WindowManager;
28c2a8d151dcd8e04dd67e5adbdf68b9795932ad82Amith Yamasaniimport android.widget.TextView;
29c2a8d151dcd8e04dd67e5adbdf68b9795932ad82Amith Yamasani
30c2a8d151dcd8e04dd67e5adbdf68b9795932ad82Amith Yamasaniimport com.android.internal.R;
315e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasaniimport com.android.internal.annotations.GuardedBy;
327805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani
337805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani/**
347805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani * Dialog to show when a user switch it about to happen. The intent is to snapshot the screen
357805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani * immediately after the dialog shows so that the user is informed that something is happening
367805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani * in the background rather than just freeze the screen and not know if the user-switch affordance
377805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani * was being handled.
387805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani */
399c79504225f60c72c947220b6aca928f11279e1cCraig Mautnerfinal class UserSwitchingDialog extends AlertDialog
409c79504225f60c72c947220b6aca928f11279e1cCraig Mautner        implements ViewTreeObserver.OnWindowShownListener {
417805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani    private static final String TAG = "ActivityManagerUserSwitchingDialog";
427805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani
435e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani    // Time to wait for the onWindowShown() callback before continuing the user switch
445e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani    private static final int WINDOW_SHOWN_TIMEOUT_MS = 3000;
455e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani
467805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani    private final ActivityManagerService mService;
477805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani    private final int mUserId;
485e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani    private static final int MSG_START_USER = 1;
495e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani    @GuardedBy("this")
505e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani    private boolean mStartedUser;
517805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani
527805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani    public UserSwitchingDialog(ActivityManagerService service, Context context,
537805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani            int userId, String userName, boolean aboveSystem) {
547805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani        super(context);
557805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani
567805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani        mService = service;
577805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani        mUserId = userId;
58c2a8d151dcd8e04dd67e5adbdf68b9795932ad82Amith Yamasani
59c2a8d151dcd8e04dd67e5adbdf68b9795932ad82Amith Yamasani        // Set up the dialog contents
607805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani        setCancelable(false);
61c2a8d151dcd8e04dd67e5adbdf68b9795932ad82Amith Yamasani        Resources res = getContext().getResources();
62c2a8d151dcd8e04dd67e5adbdf68b9795932ad82Amith Yamasani        // Custom view due to alignment and font size requirements
63c2a8d151dcd8e04dd67e5adbdf68b9795932ad82Amith Yamasani        View view = LayoutInflater.from(getContext()).inflate(R.layout.user_switching_dialog, null);
64c2a8d151dcd8e04dd67e5adbdf68b9795932ad82Amith Yamasani        ((TextView) view.findViewById(R.id.message)).setText(
65c2a8d151dcd8e04dd67e5adbdf68b9795932ad82Amith Yamasani                res.getString(com.android.internal.R.string.user_switching_message, userName));
66c2a8d151dcd8e04dd67e5adbdf68b9795932ad82Amith Yamasani        setView(view);
67c2a8d151dcd8e04dd67e5adbdf68b9795932ad82Amith Yamasani
687805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani        if (aboveSystem) {
697805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani            getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
707805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani        }
717805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani        WindowManager.LayoutParams attrs = getWindow().getAttributes();
727805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani        attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR |
737805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani                WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
747805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani        getWindow().setAttributes(attrs);
757805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani    }
767805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani
777805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani    @Override
787805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani    public void show() {
799c79504225f60c72c947220b6aca928f11279e1cCraig Mautner        // Slog.v(TAG, "show called");
807805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani        super.show();
819c79504225f60c72c947220b6aca928f11279e1cCraig Mautner        final View decorView = getWindow().getDecorView();
829c79504225f60c72c947220b6aca928f11279e1cCraig Mautner        if (decorView != null) {
839c79504225f60c72c947220b6aca928f11279e1cCraig Mautner            decorView.getViewTreeObserver().addOnWindowShownListener(this);
849c79504225f60c72c947220b6aca928f11279e1cCraig Mautner        }
855e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani        // Add a timeout as a safeguard, in case a race in screen on/off causes the window
865e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani        // callback to never come.
875e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_USER),
885e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani                WINDOW_SHOWN_TIMEOUT_MS);
897805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani    }
907805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani
919c79504225f60c72c947220b6aca928f11279e1cCraig Mautner    @Override
929c79504225f60c72c947220b6aca928f11279e1cCraig Mautner    public void onWindowShown() {
939c79504225f60c72c947220b6aca928f11279e1cCraig Mautner        // Slog.v(TAG, "onWindowShown called");
945e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani        startUser();
955e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani    }
965e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani
975e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani    void startUser() {
985e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani        synchronized (this) {
995e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani            if (!mStartedUser) {
1005e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani                mService.startUserInForeground(mUserId, this);
1015e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani                mStartedUser = true;
1025e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani                final View decorView = getWindow().getDecorView();
1035e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani                if (decorView != null) {
1045e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani                    decorView.getViewTreeObserver().removeOnWindowShownListener(this);
1055e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani                }
1065e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani                mHandler.removeMessages(MSG_START_USER);
1075e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani            }
1087805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani        }
1099c79504225f60c72c947220b6aca928f11279e1cCraig Mautner    }
1105e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani
1115e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani    private final Handler mHandler = new Handler() {
1125e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani        @Override
1135e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani        public void handleMessage(Message msg) {
1145e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani            switch (msg.what) {
1155e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani                case MSG_START_USER:
1165e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani                    startUser();
1175e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani                    break;
1185e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani            }
1195e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani        }
1205e5cb463b6e2540a7ef6c261ba5fed074be536e1Amith Yamasani    };
1217805a10c86a2de9fb5ddf41d63075eef342a59eaAmith Yamasani}
122