Adding a warning dialog before restarting demo session

Instead of immediately restarting the demo after user inactivity timeout,
now the system shows a warning dialog that counts down for 6 seconds,
during which the user can choose to continue the current session or
restart the session immediately.

Bug: 29520255
Change-Id: I060f700dcbbb6f64ae5fe95e3f3027bc3c33b38d
This commit is contained in:
Suprabh Shukla
2016-06-14 16:28:23 -07:00
parent 6d296286e4
commit f38b1d7abe
4 changed files with 158 additions and 15 deletions

View File

@@ -4367,15 +4367,21 @@
<string name="negative_duration">\u2212<xliff:g id="time" example="1:14">%1$s</xliff:g></string>
<!-- Title of notification to start a new demo session when device is in retail mode [CHAR LIMIT=NONE] -->
<string name="reset_retail_demo_mode_title">Restart Session</string>
<string name="reset_retail_demo_mode_title">Reset device?</string>
<!-- Text of notification to start a new demo session when device is in retail mode [CHAR LIMIT=NONE] -->
<string name="reset_retail_demo_mode_text">Tap to start a new demo session</string>
<string name="reset_retail_demo_mode_text">Tap to reset device</string>
<!-- Text of dialog shown when starting a demo user for the first time [CHAR LIMIT=40] -->
<string name="demo_starting_message">Starting demo</string>
<string name="demo_starting_message">Starting demo\u2026</string>
<!-- Text of dialog shown when starting a new demo user in retail demo mode [CHAR LIMIT=40] -->
<string name="demo_restarting_message">Restarting session</string>
<string name="demo_restarting_message">Resetting device\u2026</string>
<!-- Title of the dialog shown when user inactivity times out in retail demo mode [CHAR LIMIT=40] -->
<string name="demo_user_inactivity_timeout_title">Reset device?</string>
<!-- Warning message shown when user inactivity times out in retail demo mode [CHAR LIMIT=none] -->
<string name="demo_user_inactivity_timeout_countdown">You\'ll lose any changes and the demo will start again in <xliff:g id="timeout" example="9">%1$s</xliff:g> seconds\u2026</string>
<!-- Text of button to allow user to abort countdown and continue current session in retail demo mode [CHAR LIMIT=40] -->
<string name="demo_user_inactivity_timeout_left_button">Cancel</string>
<!-- Text of button to allow user to abort countdown and immediately start another session in retail demo mode [CHAR LIMIT=40] -->
<string name="demo_user_inactivity_timeout_right_button">Reset now</string>
<!-- Title of notification shown when device has been forced to safe mode after a security compromise. -->
<string name="audit_safemode_notification">Factory reset to use this device without restrictions</string>

View File

@@ -1892,6 +1892,10 @@
<java-symbol type="string" name="audit_safemode_notification_details" />
<java-symbol type="string" name="reset_retail_demo_mode_title" />
<java-symbol type="string" name="reset_retail_demo_mode_text" />
<java-symbol type="string" name="demo_user_inactivity_timeout_title" />
<java-symbol type="string" name="demo_user_inactivity_timeout_countdown" />
<java-symbol type="string" name="demo_user_inactivity_timeout_left_button" />
<java-symbol type="string" name="demo_user_inactivity_timeout_right_button" />
<java-symbol type="layout" name="resolver_list" />
<java-symbol type="id" name="resolver_list" />

View File

@@ -25,6 +25,7 @@ import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.IPackageManager;
@@ -44,12 +45,13 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.util.Slog;
import com.android.internal.os.BackgroundThread;
import com.android.internal.R;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
import com.android.server.am.UserInactivityCountdownDialog.OnCountDownExpiredListener;
import java.io.File;
public class RetailDemoModeService extends SystemService {
@@ -65,6 +67,8 @@ public class RetailDemoModeService extends SystemService {
private static final long SCREEN_WAKEUP_DELAY = 2500;
private static final long USER_INACTIVITY_TIMEOUT = 30000;
private static final long WARNING_DIALOG_TIMEOUT = 6000;
private static final long MILLIS_PER_SECOND = 1000;
boolean mDeviceInDemoMode = false;
private ActivityManagerService mAms;
@@ -110,7 +114,7 @@ public class RetailDemoModeService extends SystemService {
mWakeLock.acquire();
break;
case MSG_INACTIVITY_TIME_OUT:
IPackageManager pm = AppGlobals.getPackageManager();
final IPackageManager pm = AppGlobals.getPackageManager();
int enabledState = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
String demoLauncherComponent = getContext().getResources()
.getString(R.string.config_demoModeLauncherComponent);
@@ -122,8 +126,8 @@ public class RetailDemoModeService extends SystemService {
// XXX: shouldn't happen
}
if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED) {
Slog.i(TAG, "Restarting session due to user inactivity timeout");
sendEmptyMessage(MSG_START_NEW_SESSION);
Slog.i(TAG, "User inactivity timeout reached");
showInactivityCountdownDialog();
}
break;
case MSG_START_NEW_SESSION:
@@ -131,7 +135,8 @@ public class RetailDemoModeService extends SystemService {
Slog.d(TAG, "Switching to a new demo user");
}
removeMessages(MSG_START_NEW_SESSION);
UserInfo demoUser = getUserManager().createUser(DEMO_USER_NAME,
removeMessages(MSG_INACTIVITY_TIME_OUT);
final UserInfo demoUser = getUserManager().createUser(DEMO_USER_NAME,
UserInfo.FLAG_DEMO | UserInfo.FLAG_EPHEMERAL);
if (demoUser != null) {
setupDemoUser(demoUser);
@@ -142,6 +147,25 @@ public class RetailDemoModeService extends SystemService {
}
}
private void showInactivityCountdownDialog() {
UserInactivityCountdownDialog dialog = new UserInactivityCountdownDialog(getContext(),
WARNING_DIALOG_TIMEOUT, MILLIS_PER_SECOND);
dialog.setPositiveButtonClickListener(null);
dialog.setNegativeButtonClickListener(new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mHandler.sendEmptyMessage(MSG_START_NEW_SESSION);
}
});
dialog.setOnCountDownExpiredListener(new OnCountDownExpiredListener() {
@Override
public void onCountDownExpired() {
mHandler.sendEmptyMessage(MSG_START_NEW_SESSION);
}
});
dialog.show();
}
public RetailDemoModeService(Context context) {
super(context);
}
@@ -167,7 +191,7 @@ public class RetailDemoModeService extends SystemService {
return mResetDemoPendingIntent;
}
void setupDemoUser(UserInfo userInfo) {
private void setupDemoUser(UserInfo userInfo) {
UserManager um = getUserManager();
UserHandle user = UserHandle.of(userInfo.id);
LockPatternUtils lockPatternUtils = new LockPatternUtils(getContext());
@@ -230,13 +254,13 @@ public class RetailDemoModeService extends SystemService {
UserHandle.USER_SYSTEM);
}
boolean isDeviceProvisioned() {
private boolean isDeviceProvisioned() {
return Settings.Global.getInt(
getContext().getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) != 0;
}
private boolean deleteDemoFolderContents() {
File dir = Environment.getDataPreloadsDemoDirectory();
final File dir = Environment.getDataPreloadsDemoDirectory();
Slog.i(TAG, "Deleting contents of " + dir);
return FileUtils.deleteContents(dir);
}
@@ -286,7 +310,7 @@ public class RetailDemoModeService extends SystemService {
if (DEBUG) {
Slog.d(TAG, "onSwitchUser: " + userId);
}
UserInfo ui = getUserManager().getUserInfo(userId);
final UserInfo ui = getUserManager().getUserInfo(userId);
if (!ui.isDemo()) {
Slog.wtf(TAG, "Should not allow switch to non-demo user in demo mode");
return;

View File

@@ -0,0 +1,109 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.server.am;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.os.CountDownTimer;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.TextView;
import com.android.internal.R;
public class UserInactivityCountdownDialog extends AlertDialog {
private OnCountDownExpiredListener mOnCountDownExpiredListener;
private View mDialogView;
private CountDownTimer mCountDownTimer;
private long mCountDownDuration;
private long mRefreshInterval;
protected UserInactivityCountdownDialog(Context context, long duration, long refreshInterval) {
super(context);
mCountDownDuration = duration;
mRefreshInterval = refreshInterval;
mDialogView = LayoutInflater.from(context).inflate(R.layout.alert_dialog, null);
String msg = context.getString(R.string.demo_user_inactivity_timeout_countdown, duration);
getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
WindowManager.LayoutParams attrs = getWindow().getAttributes();
attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
getWindow().setAttributes(attrs);
setTitle(R.string.demo_user_inactivity_timeout_title);
setView(mDialogView);
setMessage(msg);
}
public void setOnCountDownExpiredListener(
OnCountDownExpiredListener onCountDownExpiredListener) {
mOnCountDownExpiredListener = onCountDownExpiredListener;
}
public void setPositiveButtonClickListener(OnClickListener onClickListener) {
setButton(Dialog.BUTTON_POSITIVE,
getContext().getString(R.string.demo_user_inactivity_timeout_left_button),
onClickListener);
}
public void setNegativeButtonClickListener(OnClickListener onClickListener) {
setButton(Dialog.BUTTON_NEGATIVE,
getContext().getString(R.string.demo_user_inactivity_timeout_right_button),
onClickListener);
}
@Override
public void show() {
super.show();
mDialogView.post(new Runnable() {
@Override
public void run() {
mCountDownTimer = new CountDownTimer(mCountDownDuration, mRefreshInterval) {
@Override
public void onTick(long millisUntilFinished) {
String msg = getContext().getResources().getString(
R.string.demo_user_inactivity_timeout_countdown,
millisUntilFinished / 1000);
((TextView) mDialogView.findViewById(R.id.message)).setText(msg);
}
@Override
public void onFinish() {
dismiss();
if (mOnCountDownExpiredListener != null)
mOnCountDownExpiredListener.onCountDownExpired();
}
}.start();
}
});
}
@Override
public void dismiss() {
super.dismiss();
if (mCountDownTimer != null) {
mCountDownTimer.cancel();
}
}
interface OnCountDownExpiredListener {
void onCountDownExpired();
}
}