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